Hallo,
Ich denke, es wäre vielleicht sinnvoll, das ganze anhand eines Moduls aufzuzeigen?
Hier einmal die Komponenten, die ich ins Auge gefasst hatte:
Blutdruck, Sauerstoffsättigung (spO2) und Puls:
MAX32664
Informationen zum Max32664: MAX32664 Ultra-Low Power Biometric Sensor Hub | Analog Devices
Das wäre dann das "Modul" dazu: Pulse Express Pulse-Ox & Heart Rate Sensor with MAX32664 – Protocentral Electronics
Github: GitHub - Protocentral/protocentral-pulse-express: Arduino Library for the ProtoCentral Pulse Express breakout board with MAX30102 and MAX32664D, used for measurement of Spo2, heartrate and BP trending.
Die Daten werden mittels den I2C Bus von dem Modul zum Arduino/ESP geschickt und dort grafisch mit der Open View GUI dargestellt: GitHub - Protocentral/protocentral_openview: GUI for plotting/storing data from ProtoCentral breakouts
Hier sind die Codbeispiele:
Arduino PPG (Pulswelle)
//////////////////////////////////////////////////////////////////////////////////////////
//
// Demo code for the protoCentral MAX32664 breakout board
//
// Author: Joice Tm
// Copyright (c) 2020 ProtoCentral
//
// |Max32664 pin label| Arduino Connection |Pin Function |
// |----------------- |---------------------|------------------|
// | SDA | A4 | Serial Data |
// | SCL | A5 | Serial Clock |
// | Vin | 5V | Power |
// | GND | Gnd | Gnd |
// | MFIO Pin | 02 | MFIO |
// | RESET Pin | 04 | Reset |
// |-----------------------------------------------------------|
//
// Place your finger on the sebsor and open arduino serial plotter to view the ppg signal.
//
// This software is licensed under the MIT License(http://opensource.org/licenses/MIT).
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
/////////////////////////////////////////////////////////////////////////////////////////
#include "max32664.h"
#include <Wire.h>
#define RESET_PIN 04
#define MFIO_PIN 02
#define RAWDATA_BUFFLEN 400
max32664 MAX32664(RESET_PIN, MFIO_PIN, RAWDATA_BUFFLEN);
void mfioInterruptHndlr(){
}
void enableInterruptPin(){
// pinMode(mfioPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(MAX32664.mfioPin), mfioInterruptHndlr, FALLING);
}
void setup(){
Serial.begin(57600);
Wire.begin();
int result = MAX32664.hubBegin();
if (result == 0){
Serial.println("Sensor started!");
}else{
//stay here.
while(1){
Serial.println("Could not communicate with the sensor!!!");
delay(30000);
}
}
bool ret = MAX32664.configRawdataMode();
while(!ret){
Serial.println("failed to configure Raw data mode, trying again in 30 Sec");
ret = MAX32664.configRawdataMode();
delay(30000);
}
Serial.println("Geting the device ready..");
delay(2000);
}
void loop(){
static int16_t irBuff[RAWDATA_BUFFLEN];
//static int16_t redBuff[RAWDATA_BUFFLEN];
uint8_t num_samples = MAX32664.readRawSamples(irBuff);
///Serial.print("num samples ");
//Serial.println(num_samples);
for(int i=0; i<num_samples; i++){
Serial.println(irBuff[i]);
//Serial.println(redBuff[i]);
delay(3);
}
}
Arduino BP (Blutdruck)
//////////////////////////////////////////////////////////////////////////////////////////
//
// Demo code for the protoCentral MAX32664 breakout board
//
// Author: Joice Tm
// Copyright (c) 2020 ProtoCentral
//
// |Max32664 pin label| Arduino Connection |Pin Function |
// |----------------- |---------------------|------------------|
// | SDA | A4 | Serial Data |
// | SCL | A5 | Serial Clock |
// | Vin | 5V | Power |
// | GND | Gnd | Gnd |
// | MFIO Pin | 02 | MFIO |
// | RESET Pin | 04 | Reset |
// |-----------------------------------------------------------|
//
// This software is licensed under the MIT License(http://opensource.org/licenses/MIT).
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
/////////////////////////////////////////////////////////////////////////////////////////
#include <Wire.h>
#include "max32664.h"
#define RESET_PIN 04
#define MFIO_PIN 02
#define RAWDATA_BUFFLEN 250
max32664 MAX32664(RESET_PIN, MFIO_PIN, RAWDATA_BUFFLEN);
void mfioInterruptHndlr(){
//Serial.println("i");
}
void enableInterruptPin(){
//pinMode(mfioPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(MAX32664.mfioPin), mfioInterruptHndlr, FALLING);
}
void loadAlgomodeParameters(){
algomodeInitialiser algoParameters;
/* Replace the predefined values with the calibration values taken with a reference spo2 device in a controlled environt.
Please have a look here for more information, https://pdfserv.maximintegrated.com/en/an/an6921-measuring-blood-pressure-MAX32664D.pdf
https://github.com/Protocentral/protocentral-pulse-express/blob/master/docs/SpO2-Measurement-Maxim-MAX32664-Sensor-Hub.pdf
*/
algoParameters.calibValSys[0] = 120;
algoParameters.calibValSys[1] = 122;
algoParameters.calibValSys[2] = 125;
algoParameters.calibValDia[0] = 80;
algoParameters.calibValDia[1] = 81;
algoParameters.calibValDia[2] = 82;
algoParameters.spo2CalibCoefA = 1.5958422;
algoParameters.spo2CalibCoefB = -34.659664;
algoParameters.spo2CalibCoefC = 112.68987;
MAX32664.loadAlgorithmParameters(&algoParameters);
}
void setup(){
Serial.begin(57600);
Wire.begin();
loadAlgomodeParameters();
int result = MAX32664.hubBegin();
if (result == CMD_SUCCESS){
Serial.println("Sensorhub begin!");
}else{
//stay here.
while(1){
Serial.println("Could not communicate with the sensor! please make proper connections");
delay(5000);
}
}
bool ret = MAX32664.startBPTcalibration();
while(!ret){
delay(10000);
Serial.println("failed calib, please retsart");
//ret = MAX32664.startBPTcalibration();
}
delay(1000);
//Serial.println("start in estimation mode");
ret = MAX32664.configAlgoInEstimationMode();
while(!ret){
//Serial.println("failed est mode");
ret = MAX32664.configAlgoInEstimationMode();
delay(10000);
}
//MAX32664.enableInterruptPin();
Serial.println("Getting the device ready..");
delay(1000);
}
void loop(){
uint8_t num_samples = MAX32664.readSamples();
if(num_samples){
Serial.print("sys = ");
Serial.print(MAX32664.max32664Output.sys);
Serial.print(", dia = ");
Serial.print(MAX32664.max32664Output.dia);
Serial.print(", hr = ");
Serial.print(MAX32664.max32664Output.hr);
Serial.print(" spo2 = ");
Serial.println(MAX32664.max32664Output.spo2);
}
delay(100);
}
Dann gibt es auch noch den Open View Code
//////////////////////////////////////////////////////////////////////////////////////////
//
// Demo code for the protoCentral MAX32664 breakout board
//
// Author: Joice Tm
// Copyright (c) 2020 ProtoCentral
//
// This example plots the raw PPG signal through serial UART on openview processing GUI.
// GUI URL: https://github.com/Protocentral/protocentral_openview.git
//
// |Max32664 pin label| Arduino Connection |Pin Function |
// |----------------- |---------------------|------------------|
// | SDA | A4 | Serial Data |
// | SCL | A5 | Serial Clock |
// | Vin | 5V | Power |
// | GND | Gnd | Gnd |
// | MFIO Pin | 02 | MFIO |
// | RESET Pin | 04 | Reset |
// |-----------------------------------------------------------|
//
// Place your finger on the sebsor and open arduino serial plotter to view the ppg signal.
//
// This software is licensed under the MIT License(http://opensource.org/licenses/MIT).
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
/////////////////////////////////////////////////////////////////////////////////////////
#include "max32664.h"
#include <Wire.h>
#define CES_CMDIF_PKT_START_1 0x0A
#define CES_CMDIF_PKT_START_2 0xFA
#define CES_CMDIF_TYPE_DATA 0x02
#define CES_CMDIF_PKT_STOP 0x0B
#define DATA_LEN 9
#define ZERO 0
#define RESET_PIN 04
#define MFIO_PIN 02
#define RAWDATA_BUFFLEN 200
volatile char DataPacket[DATA_LEN];
const char DataPacketFooter[2] = {ZERO, CES_CMDIF_PKT_STOP};
const char DataPacketHeader[5] = {CES_CMDIF_PKT_START_1, CES_CMDIF_PKT_START_2, DATA_LEN, ZERO, CES_CMDIF_TYPE_DATA};
max32664 MAX32664(RESET_PIN, MFIO_PIN, RAWDATA_BUFFLEN);
void mfioInterruptHndlr(){
}
void enableInterruptPin(){
// pinMode(mfioPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(MAX32664.mfioPin), mfioInterruptHndlr, FALLING);
}
void sendDataThroughUart(int16_t ir, int16_t red){
DataPacket[0] = ir;
DataPacket[1] = ir >> 8;
DataPacket[2] = red;
DataPacket[3] = red >> 8;
//send packet header
for(int i=0; i<5; i++){
Serial.write(DataPacketHeader[i]);
}
//send actual data
for(int i=0; i<DATA_LEN; i++){
Serial.write(DataPacket[i]);
}
//send packet footer
for(int i=0; i<2; i++){
Serial.write(DataPacketFooter[i]);
}
}
void setup(){
Serial.begin(57600);
Wire.begin();
int result = MAX32664.hubBegin();
if (result == 0){
Serial.println("Sensor started!");
}else{
//stay here.
while(1){
Serial.println("Could not communicate with the sensor!!!");
delay(30000);
}
}
bool ret = MAX32664.configRawdataMode();
while(!ret){
Serial.println("failed to configure Raw data mode, trying again in 30 Sec");
ret = MAX32664.configRawdataMode();
delay(30000);
}
Serial.println("Geting the device ready..");
delay(2000);
}
void loop(){
static int16_t irBuff[RAWDATA_BUFFLEN];
static int16_t redBuff[RAWDATA_BUFFLEN];
uint8_t num_samples = MAX32664.readRawSamples(irBuff, redBuff);
///Serial.print("num samples ");
//Serial.println(num_samples);
for(int i=0; i<num_samples; i++){
sendDataThroughUart(irBuff[i], redBuff[i]);
delay(2);
}
}
Aktuell habe ich folgendes Modul erstmal: ProtoCentral MAX30205 Wearable Body Thermometer Breakout Board – QWIIC compatible – Protocentral Electronics
Bei diesem haben wir es so gemacht, dass der ESP sich mit dem Wifi verbindet und die Daten an eine mysql Datei schickt, danach wird sie mit einem pho ausgelesen:
Cod des Moduls
PHP zur Darstellung
//PHP Script to Visualize contents in the database in the form of a chart
<?php
$servername = "localhost";
// REPLACE with your Database name
$dbname = "web290_db14";
// REPLACE with Database user
$username = "web290_14";
// REPLACE with Database user password
$password = "swint145qAwSeD";
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$sql = "SELECT id, value1, reading_time FROM Sensor order by reading_time desc limit 40";
$result = $conn->query($sql);
while ($data = $result->fetch_assoc()){
$sensor[] = $data;
}
$readings_time = array_column($sensor, 'reading_time');
// ******* Uncomment to convert readings time array to your timezone ********
/*$i = 0;
foreach ($readings_time as $reading){
// Uncomment to set timezone to - 1 hour (you can change 1 to any number)
$readings_time[$i] = date("Y-m-d H:i:s", strtotime("$reading - 1 hours"));
// Uncomment to set timezone to + 4 hours (you can change 4 to any number)
//$readings_time[$i] = date("Y-m-d H:i:s", strtotime("$reading + 4 hours"));
$i += 1;
}*/
$value1 = json_encode(array_reverse(array_column($sensor, 'value1')), JSON_NUMERIC_CHECK);
//$value2 = json_encode(array_reverse(array_column($sensor, 'value2')), JSON_NUMERIC_CHECK);
$reading_time = json_encode(array_reverse($readings_time), JSON_NUMERIC_CHECK);
/*echo $value1;
echo $value2;
echo $reading_time;*/
$result->free();
$conn->close();
?>
<!DOCTYPE html>
<html>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://code.highcharts.com/highcharts.js"></script>
<style>
body {
min-width: 310px;
max-width: 1280px;
height: 500px;
margin: 0 auto;
}
h2 {
font-family: Arial;
font-size: 2.5rem;
text-align: center;
}
</style>
<body>
<h2>Temperature Data</h2>
<div id="chart-Temperature" class="container"></div>
<script>
var value1 = <?php echo $value1; ?>;
//var value2 = <?php echo $value2; ?>;
var reading_time = <?php echo $reading_time; ?>;
var chartT = new Highcharts.Chart({
chart:{ renderTo : 'chart-Temperature' },
title: { text: 'MAX30205 Temperature Data' },
series: [{
showInLegend: false,
data: value1
}],
plotOptions: {
line: { animation: false,
dataLabels: { enabled: true }
},
series: { color: '#059e8a' }
},
xAxis: {
type: 'datetime',
categories: reading_time
},
yAxis: {
title: { text: 'Temperature (in degrees)' }
},
credits: { enabled: false }
});
/*
var chartH = new Highcharts.Chart({
chart:{ renderTo:'chart-SPO2' },
title: { text: 'MAX30102 SPO2' },
series: [{
showInLegend: false,
data: value2
}],
plotOptions: {
line: { animation: false,
dataLabels: { enabled: true }
}
},
xAxis: {
type: 'datetime',
//dateTimeLabelFormats: { second: '%H:%M:%S' },
categories: reading_time
},
yAxis: {
title: { text: 'SPO2' }
},
credits: { enabled: false }
});
*/
</script>
</body>
</html>
PHP das in die Datenbank schreibt
/PHP script to post data to server
<?php
$servername = "localhost";
// REPLACE with your Database name
$dbname = "web290_db14";
// REPLACE with Database user
$username = "web290_14";
// REPLACE with Database user password
$password = "swint145qAwSeD";
// Keep this API Key value to be compatible with the ESP32 code. If you change this value here, the ESP32 sketch needs to match
$api_key_value = "tPmAT5Ab3j7F9";
$api_key = $value1 ="";
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$api_key = test_input($_POST["api_key"]);
if($api_key == $api_key_value) {
$value1 = test_input($_POST["value1"]);
//$value2 = test_input($_POST["value2"]);
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$sql = "INSERT INTO Sensor (value1)
VALUES ('" . $value1 . "')";
if ($conn->query($sql) === TRUE) {
echo "New record created successfully";
}
else {
echo "Error: " . $sql . "<br>" . $conn->error;
}
$conn->close();
}
else {
echo "Wrong API Key provided.";
}
}
else {
echo "No data posted with HTTP POST.";
}
function test_input($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
}
ESP Cod
//////////////////////////////////////////////////////////////////////////////////////////
//
// Arduino example for the MAX30205 body temperature sensor breakout board
//
// Author: Ashwin Whitchurch
// Copyright (c) 2018 ProtoCentral
//
// This software is licensed under the MIT License(http://opensource.org/licenses/MIT).
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// For information on how to use, visit https://github.com/protocentral/ProtoCentral_MAX30205
/////////////////////////////////////////////////////////////////////////////////////////
/*
This program Print temperature on terminal
Hardware Connections (Breakoutboard to Arduino):
Vin - 5V (3.3V is allowed)
GND - GND
SDA - A4 (or SDA)
SCL - A5 (or SCL)
*/
#include <WiFi.h>
#include <HTTPClient.h>
#include <Wire.h>
#include "Protocentral_MAX30205.h"
MAX30205 tempSensor;
// Replace with your network credentials
const char* ssid = "WLAN1-000727";
const char* password = "swint145!";
// REPLACE with your Domain name and URL path or IP address with path
const char* serverName = "webseite.org/post-data.php";
// Keep this API Key value to be compatible with the PHP code provided in the project page.
// If you change the apiKeyValue value, the PHP file /post-data.php also needs to have the same key
String apiKeyValue = "tPmAT5Ab3j7F9";
void setup() {
// put your setup code here, to run once:
Wire.begin();
Serial.begin(9600);
WiFi.begin(ssid, password);
Serial.println("Connecting");
while(WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to WiFi network with IP Address: ");
Serial.println(WiFi.localIP());
tempSensor.begin(); // set continuos mode, active mode
}
void loop() {
float temp = tempSensor.getTemperature(); // read temperature for every 100ms
Serial.print(temp ,2);
Serial.println("'c" );
//Check WiFi connection status
if(WiFi.status()== WL_CONNECTED){
HTTPClient http;
// Your Domain name with URL path or IP address with path
http.begin(serverName);
// Specify content-type header
http.addHeader("Content-Type", "application/x-www-form-urlencoded");
// Prepare your HTTP POST request data
String httpRequestData = "api_key=" + apiKeyValue + "&value1=" + String(temp) + "";
// Send HTTP POST request
int httpResponseCode = http.POST(httpRequestData);
if (httpResponseCode>0) {
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
}
else {
Serial.print("Error code: ");
Serial.println(httpResponseCode);
}
// Free resources
http.end();
}
else {
Serial.println("WiFi Disconnected");
}
delay(1000);
}
Eine Idee wäre nun das verlinkte Modul gleich zu realisieren. Also einen Arduino/ESP drann, dann die Daten an das php file und in die mysql Datenbank.
Wäre das so verständlich beschrieben?
LG