Sensor Puck


1. Waht is the Sensor Puck?


The sensor puck demonstrates Silicon Laboratories optical sensor Si1147-M01Keine Zugangsberechtigung, humidity and temperature sensor Si7021Keine Zugangsberechtigung and Microcontroller (EFM32G210Keine Zugangsberechtigung Gecko). The data is broadcast using a Bluetooth Low Energy (BLE) module.

Data and can be displayed on a mobile device (Apple iOS or Android) that supports the BLE protocol.

Product page:
http://www.silabs.com/products/sensors/Pages/environmental-biometric-sensor-puck.aspx





2. Components


  • Microcontroller EFM32G210Keine Zugangsberechtigung, ARM Cortex-M3
  • Switched voltage regulator TS3310Keine Zugangsberechtigung
  • Optical sensor Si1147-M01Keine Zugangsberechtigung (UV index, ambient light, pulse rate)
  • Humidity and temperature sensor Si7021Keine Zugangsberechtigung
  • Bluetooth Smart Chip BCM20732iKeine Zugangsberechtigung, ARM Cortex-M3
  • Epson 24 MHz FA-238



3. Receive data on Raspberry Pi


There is an App for iOS and Android, but I would like to see the Sensor Puck data on my living room screen (Homienaut).

This python script helped me a lot to start receiving and converting the data from sensor puck: http://amperture.com/?p=23

Sensor puck sends the data in as advertising packet. This means in terms of Bluetooth Smart there is no connection required. The Sensor Puck is the broadcaster and the Homienaut is the observer.
I found this broadcast format specification very useful to determinate additional parameters of the sensor (ambient light, UV index, battery voltage and pulse rate).
http://community.silabs.com/mgrfq63796/attachments/mgrfq63796/6/10653/1/Silicon%20Labs%20Sensor%20Puck%20App.pdf

I wrote two applications: a command line application and a GUI application in python.


4. Terminal Application


I wrote this code based on the implementation from http://amperture.com/?p=23

The Sensor Puck has two modes. Usually Sensor Puck is in enviromental mode. If you put a finger on the optical sensor, the puck switches into biometric.

My script delivers the following parameters.

Enviromental Mode

Humidity: 51.4 %
Temperature: 20.5 C
Ambient light: 1.5 Lux
UV index: 0.0
Battery voltage: 3.0 V


Biometric Mode

HRM state: Active
Pulse rate: 72 bpm




# Code based on the implementation from http://amperture.com/?p=23
# With additions by Andreas Tobola, October 2015, http://tnotes.de/SensorPuck

import subprocess
import os

proc = subprocess.Popen(['hcidump --raw'], stdout=subprocess.PIPE, shell=True)

hrmStateStr = ['Idle', 'No Signal', 'Acquiring', 'Active', 'Invalid', 'Error']

while True:
    line = proc.stdout.readline()    
    if ">" not in line:        
        hexarray = line.split()
        N = len(hexarray)
       
        os.system('clear')
       
        if N==14:            
            print "== Enviromental Mode ==\n"
           
            # Humidity uint16 deciprecent
            humidity = (int(hexarray[6], 16) << 8) + int(hexarray[5], 16)
            humidity = float(humidity)/10
           
            # Temperature int16 decidegrees (can be negative -> twos complement)
            temp = (int(hexarray[8], 16) << 8) + int(hexarray[7], 16)
            temp = float(temp)/10

            # Ambient Light uint16 lux/2
            amblight = (int(hexarray[10], 16) << 8) + int(hexarray[9], 16)
            amblight = float(amblight)/2
           
            # UV Index uint8 index
            uvidx = int(hexarray[11], 16)
           
            # Battery Voltage uint8 decivolts
            vbat = int(hexarray[12], 16)
            vbat = float(vbat)/10
           
            print u"Humidity: %.1f " %humidity + '%'
            print u"Temperature: %.1f \xb0C" %temp
            print "Ambient light: %.1f Lux" %amblight
            print "UV index: %.1f" %uvidx
            print "Battery voltage: %.1f V" %vbat
        elif N==18:
            print "== Biometric Mode ==\n"      
           
            # HRM State uint8 none
            hrmState = int(hexarray[5], 16)
            print "HRM state: " + hrmStateStr[hrmState]
           
            # HRM Rate uint8 bpm
            pulseRate = int(hexarray[6], 16)
            print "Pulse rate: " + str(pulseRate) + " bpm"
           
            # HRM Sample Array uint16[5] none
            # ...
        print " "



The Sensor Puck has two modes Enviromental and Biometric Mode.

If the finger is on the optical sensor, the sensor switches into Biometric Mode.

Depending on the mode the sensor broadcasts different data.





5. GUI Application


Additionally, I wrote a python script with GUI based using TkinterKeine Zugangsberechtigung to visualize the data.









Put your finger on the optical sensor of the Sensor Puck to measure the pulse rate.





#!/usr/bin/python
# Thos is a GUI version of the Sensor Puck Script at http://tnotes.de/SensorPuck
# Andreas Tobola, October 2015
# Version 1.4

from Tkinter import *
import time
import thread
import subprocess
import os

# XML-RPC to provide the sensor data for other processes
from SimpleXMLRPCServer import SimpleXMLRPCServer
from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler



bgcolor = 'black';
fgcolor = 'light blue'                                                                            
fgcolorerr = 'Orange Red'

#bgcolor = '#A0A0F8';
#fgcolor = '#302040'                                                                            
#fgcolorerr = '#801020'


temp = 0.0
amblight = -1.0

def getTemperature():
    return temp
   
def getAmbLight():
    return amblight    

def threadSensorDecoder():
    global tTimeOutObserver
    global temp
    global amblight
    while 1:        
        line = proc.stdout.readline()    
       
        if ">" not in line:        
            hexarray = line.split()
            N = len(hexarray)
           
            tTimeOutObserver = time.time() + 42
           
            if N==14:            

                # Humidity uint16 deciprecent
                humidity = (int(hexarray[6], 16) << 8) + int(hexarray[5], 16)
                humidity = float(humidity)/10

                # Temperature int16 decidegrees (can be negative -> twos complement)
                temp = (int(hexarray[8], 16) << 8) + int(hexarray[7], 16)
                temp = float(temp)/10

                # Ambient Light uint16 lux/2
                amblight = (int(hexarray[10], 16) << 8) + int(hexarray[9], 16)
                amblight = float(amblight)/2

                # UV Index uint8 index
                uvidx = int(hexarray[11], 16)

                # Battery Voltage uint8 decivolts
                vbat = int(hexarray[12], 16)
                vbat = float(vbat)/10
                               
                laSensData['text'] = u'Temperature: %.1f \xb0C \n Humidity: %.1f ' %(temp, humidity) + '%' + ' \n Ambient light: %.1f Lux \n UV index: %d \n Battery voltage: %.1f V' %(amblight, uvidx, vbat)
               
                txtExtra = '';
                if humidity > 58.0:
                    txtExtra += 'Ventilate the room.\n'
                if temp > 25.0:
                    txtExtra += 'It\'s incredible hot in here!\n'
                elif temp > 22.5:
                    txtExtra += 'It\'s hot in here.\n'
                elif temp < 18.0:
                    txtExtra += 'It\'s cold in here!\n'
                if vbat < 2.7:
                    txtExtra += 'Low sensor battery.\n'
                   
                laExtra['text'] = txtExtra;
               

            elif N==18:                

                # HRM State uint8 none
                hrmState = int(hexarray[5], 16)

                # HRM Rate uint8 bpm
                pulseRate = int(hexarray[6], 16)

                # HRM Sample Array uint16[5] none
                # maybe one day...
               
                laSensData['text'] = u'Pulse Sensor Mode \n Sensor state: %s \n Pulse rate: %d bpm' %(hrmStateStr[hrmState], pulseRate)
               
                txtExtra = '';
                if hrmState == 3:
                    if pulseRate > 120:
                        txtExtra += 'Your pulse rate is high.\n'
                    if pulseRate < 50:
                        txtExtra += 'Your pulse rate is low.\n'
                laExtra['text'] = txtExtra;

               
               

def threadSensorObserver():
   
    global temp
    while 1:  
        time.sleep(2)
        if time.time() > tTimeOutObserver:
            laSensData['text'] = '';
            laExtra['text'] = 'Sensor out of range.';
            temp = 0;
     

   
def threadSensorDataServer():

    # Restrict to a particular path.
    class RequestHandler(SimpleXMLRPCRequestHandler):
        rpc_paths = ('/RPC2',)
   
    # Create server
    server = SimpleXMLRPCServer(("localhost", 8201), requestHandler=RequestHandler)
    server.register_function(getTemperature, 'getTemperature')
    server.register_function(getAmbLight, 'getAmbLight')
   
   
   
    server.serve_forever()    # Run the server's main loop
   
     

               
tTimeOutObserver = time.time() + 12

master = Tk()

master.configure(background=bgcolor)
fontSensData = ("Helvetica",30,"bold");

w = Label(master, text="Sensor Puck", font = ("Helvetica",50,"bold"), bg=bgcolor, fg=fgcolor )
w.pack()

laSensData = Label(master, text="...", font = fontSensData, bg=bgcolor, fg=fgcolor )
laSensData.pack()

laExtra = Label(master, text="", font = fontSensData, bg=bgcolor, fg=fgcolorerr )
laExtra.pack()

proc = subprocess.Popen(['sudo hcidump --raw'], stdout=subprocess.PIPE, shell=True)

hrmStateStr = ['Idle', 'No Signal', 'Acquiring', 'Active', 'Invalid', 'Error']


try:
   thread.start_new_thread( threadSensorObserver, () )
   thread.start_new_thread( threadSensorDecoder, () )
   thread.start_new_thread( threadSensorDataServer, () )
except:
   print "Error: unable to start thread"
    


   
mainloop()


Just in case you ask yourself the question, why I didn't used the escape char %% in my formated string constructions. Well, %% is the escape char for end of code in my Wiki. So I use + '%' + instead to be able to post this code here. But both solution deliver an equal result.


6. Sensor Puck Firmware Modifications


Change advertising period from 500 ms
ble.c
BLE_SetAdvertisingParameters(800, 0, 800, 0);

to 10 seconds advertising periods (only in envirometal mode).
ble.c
BLE_SetAdvertisingParameters(16000, 0, 16000, 0);


Change sensor data update function from 1 second
sensor_puck.h
#define PERIODIC_UPDATE_MS            1000

to 10 seconds.
sensor_puck.h
#define PERIODIC_UPDATE_MS            10000


Average current reduction from ~225 µA to ~70 µA @ 3 V in environmental mode.





Siehe auch

There are no comments on this page. [Add comment]

Valid XHTML 1.0 Transitional :: Valid CSS :: Powered by WikkaWiki