Irak MayerStephanie VicarteElizabeth Vicarte
Published © GPL3+

MoBitals

A mobile device for global first responders to emergencies, epidemics, and natural disasters that allows you to check on vitals

IntermediateFull instructions providedOver 1 day132
MoBitals

Things used in this project

Hardware components

LoPy4
Pycom LoPy4
×1
Pycom Pytrack
×1
Mikroe Heart Rate 4 click
×1
Mikroe Fever click
×1
Grove - 4 Pin Female Jumper to Grove 4 Pin Conversion Cable
×1
0.96 Inch OLED Module 12864 128x64
×1
Grove I2C Hub - 6 Port
×1

Software apps and online services

Visual Studio Code. MicroPython Extension
Pymakr Plugin
Pycom Pymakr Plugin
PyCharm Community Edition

Story

Read more

Schematics

MoBitals

MoBitals Schematic Diagram

Code

V2Record.py

Python
This program contacts the SigFox backend, inquires for the devices register in the server, and pulls out the messages. Extracts the payload and decodes it.
Creates a table with the data and links the GPS with Google Maps.
######################################
#V2Record.py
#
#This program contacts the SigFox backend, inquires for the devices register in the server, and pulls out the
#messages. Extracts the payload and decodes it.
# Creates a table with the data and links the GPS with Google Maps.
#
# Copyright <2019> <VisteliLabs>
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
#associated documentation files (the "Software"), to deal in the Software without restriction,
#including without limitation the rights to use, copy, modify, merge, publish, distribute,
#sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
#subject to the following conditions:
#The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
#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.
#
#######################################
import tkinter as tk
import random, string
from tkinter import *
from tkinter.ttk import *
from sigfoxapi import Sigfox
import json
import struct
from datetime import datetime
from webbrowser import *
from tkintertable.Tables import TableCanvas
from tkintertable.TableModels import TableModel

#Simple tk class to create a window
class App:
	def __init__(self, master):
		self.main = Frame(master)
		self.main.pack(fill=BOTH,expand=1)
		master.geometry('900x500+200+100')


def callback(url):
	open_new(url)

def displayVitals(master,mydata,mydata2):
	model = TableModel()
	data = mydata
	model.importDict(data)
	fr = Frame(master)
	fr.grid(row=0,column=0,sticky='nws')
	table = TableCanvas(fr, model, width=1500,height=200,rowheaderwidth=0)
	table.createTableFrame()

	table.update()
	counter=0
	linkGMaps = {}
	for c in mydata:
		print(c)
		x1, y1, x2, y2 = table.getCellCoords(counter, 5)  # place the button at cell 1, 1
		btnText = "Btn{}".format(counter)
		print(btnText)
		linkGMaps[btnText] = tk.Button(table, text="Map IT!", fg="blue",cursor="hand2")
		linkGMaps[btnText].pack()
		print(linkGMaps)
		linkText = "https://www.google.com/maps/?q="+mydata[c]['GPS']
		print(linkText)
		linkGMaps[btnText].bind("<Button-1>", lambda e,a=linkText: callback(a))
		table.create_window(((x1 + x2) // 2, (y1 + y2) // 2), window=linkGMaps[btnText])
		counter+=1

	model = TableModel()
	data = mydata2
	model.importDict(data)
	fr = Frame(master)
	fr.grid(row=1,column=0,sticky='nws')
	table = TableCanvas(fr, model, width=1500,height=200,rowheaderwidth=0)
	table.createTableFrame()

	return

#Get the message data from the devices and formatted for displaying on a table
def createDataSigFox(sfData):
	data = {}
	data1 = {}
	names = sfData[0].keys()
	i = 0
	for n in sfData:
		rowName = 'Row_' + str(i)
		i+=1
	i = 0
	for c in sfData:
		rowName = 'Row_' + str(i)

		if(len(c['data'])>9):
			b = bytearray.fromhex(c['data'])
			dataCode = struct.unpack_from('h', b[10:12], 0)
			if (dataCode[0] != 0):
				if (dataCode[0] == 1):
					data[rowName] = {}
					data[rowName]['label'] = rowName
				elif (dataCode[0] == 2):
					data1[rowName] = {}
					data1[rowName]['label'] = rowName
				for key, value in c.items():
					if (key == 'data'):
						a = bytearray.fromhex(value)
						if (dataCode[0] == 1):
							#Uncomment the following lines if you want to see the latitude and longitude in separate columns
							#data[rowName]['Latitude']=struct.unpack_from('f', a[0:4], 0)
							#data[rowName]['Longitude'] = struct.unpack_from('f', a[4:8], 0)
							data[rowName]['GPS'] = "{:.4f},{:.4f}".format((struct.unpack_from('f', a[0:4], 0))[0],(struct.unpack_from('f', a[4:8], 0))[0])
							data[rowName]['NumPat'] = struct.unpack_from('h', a[8:10], 0)
							data[rowName][key] = value
						elif (dataCode[0] == 2):
							data1[rowName]['BPM'] = struct.unpack_from('f', a[0:4], 0)
							data1[rowName]['Temperature'] = struct.unpack_from('f', a[4:8], 0)
							data1[rowName]['Patient'] = struct.unpack_from('h', a[8:10], 0)
							data1[rowName][key] = value
					elif (key =='time'):
						mydate = datetime.fromtimestamp(int(value))
						if (dataCode[0] == 1):
							data[rowName]['TImestamp'] = mydate.strftime("%Y-%m-%d %H:%M:%S")
							#Uncomment the below line to see the raw timestamp
							#data[rowName][key] = value
						elif (dataCode[0] == 2):
							data1[rowName]['TImestamp'] = mydate.strftime("%Y-%m-%d %H:%M:%S")
							# Uncomment the below line to see the raw timestamp
							#data1[rowName][key] = value
					#uncomment the following lines if you want to see all the device information
					#else:
						#if (dataCode[0] == 1):
						#	data[rowName][key] = value
						#elif (dataCode[0] == 2):
						#	data1[rowName][key] = value
				if (dataCode[0] == 1):
					data[rowName]['GoogleMaps'] = " "

		i+=1
	return data, data1

#Connect to sigfox backend server
#Remember to change the login and password as shown on the Group - REST API page of the Sigfox backend web interface.
s = Sigfox(login, Password)
#get a list of the available devices
listDevices = s.devicetype_list()
devices = {}
devCounter =0
#Extract the device id
for dev in listDevices:
	devices[devCounter] = s.device_list(dev['id'])
	devCounter+=1

#First window device
t = Tk()
t.title(devices[0][0]['id'])
app = App(t)
master = app.main
#Get the messages from first device
mes=s.device_messages(devices[0][0]['id'])
data,data1 = createDataSigFox(mes)
displayVitals(master,data,data1)

#Second window device
t2 = Tk()
t2.title(devices[1][0]['id'])
app2 = App(t2)
master2 = app2.main
#Get the messages from second device
mes=s.device_messages(devices[1][0]['id'])
data,data1 = createDataSigFox(mes)
displayVitals(master2,data,data1)

t.mainloop()

TempPulseCheck.zip

Python
This program manages a Lopy 4 connected to a PyTrack, a Heart Rate 4 click (MIKROE-2510) board, a Fever click (MIKROE-2554) and SSD1306 display.
The program records the beats per minute heart rate and the temperature. If the temperature reach a certain threshold it codes the gps data and a counter of the number of patients. A second package with the BPM, temperature and patient number.
No preview (download only).

Credits

Irak Mayer

Irak Mayer

10 projects • 5 followers
Stephanie Vicarte

Stephanie Vicarte

10 projects • 7 followers
Elizabeth Vicarte

Elizabeth Vicarte

7 projects • 4 followers

Comments