Lua - TI SensorTag

From Domoticz
Jump to: navigation, search

Introduction

Recently I have bought a couple of SensorTag from TI SensorTag wiki for a project I have been asked to produce a feasibility study.

SensorTag is effectively an evaluation board that integrates 6 types of sensors within a tiny board:

- target thermometer
- Hygrometer
- Barometer
- Gyroscope 
- Accelerometer
- Magnetometer(Compass)  

all sensors are available via Bluetooth 4.0 (BLE) interrogating the integrated GATT server within the delivered firmware of the evaluatoin board.

Firstly I installed the SensorTag app in my Android device and, after pressing the side small button, I could connect it to gather the measures. After played a while, I noticed that Accelerometer was not sending any data to my android device so I have upgraded the SensorTag Firmware from versin 1.4 to 1.5 and all data were received.

As I have been playing with domoticz for about 6 months, I thought it would be worth to integrate also the SensorTag and collect some of the provided measures. In particular I am interested in collecting target temperature provided by IR Thermometer, ambient tempertature and humidity and, why not, even atmosferic pressure. These data, correlated with gas consumption, can easily provide characteristics of any gas heating system.

Googoling around, I noticed that only some python codes has been pubblished, exploiting bluez (opensource bluetooth stack) gatttool function. As python is a scripting language not far from LUA, and, as domoticz provide valuable functions in LUA, I started playing with those.


Bluetooth Low Energy

Job start

download bluez and install it

sudo apt-get install bluez

you may also download source code and compile it, if needed

connect your Bluetooth 4.0 (BLE) dongle to your RP (or other linux computer)

dmesg

you should see something like


[88770.582050] usb 1-1.4.3: new full-speed USB device number 13 using dwc_otg
[88770.699670] usb 1-1.4.3: New USB device found, idVendor=0a5c, idProduct=21e2
[88770.699709] usb 1-1.4.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[88770.699726] usb 1-1.4.3: Product: BCM920702 Bluetooth 4.0 Zero Touch Dongle
[88770.699740] usb 1-1.4.3: Manufacturer: Broadcom Corp
[88770.699754] usb 1-1.4.3: SerialNumber: 001986000C68

if everything is fine, issue the following command

hciconfig

and you should verify that hci interface is 'up'


hci0: Type: BR/EDR Bus: USB
BD Address: 00:19:86:00:0C:68 ACL MTU: 1021:8 SCO MTU: 64:1
UP RUNNING PSCAN
RX bytes:2096258 acl:52125 sco:0 events:155153 errors:0
TX bytes:1890903 acl:105482 sco:0 commands:38767 errors:0

.. and now start playing with the sensorscan.

To verify that SensorTag is detected press the small side button and issue

sudo hcitool lescan
LE Scan ...

B4:99:4C:64:30:B7 (unknown)
B4:99:4C:64:30:B7 SensorTag

(press ctrl C to stop LE scan)

when you have read the sensortag MAC address you may start with LUA. What you will find below, it concerns only teh following sensors: a) target temperature b) humidity c) atmosferic pressure

as actually those are my needs and domoticz already provides all the necessary to have virtual devices. all 3 above mentioned sensors integrate 3 different ambient termometers and I though it would be nice to get the measurement from all of them. So I created 4 virtual temperature sensors (3 ambient and 1 target), 1 virtual Higrometer and 1 summary sensor that includes temperature, relative humidity and atmosferic pressure (automatically, I found also a barometer virtual device in the whether tab). Totally 7 virtual devices.

Lua code

.. and finally here you are

function os.capture(cmd, raw)
  	local f = assert(io.popen(cmd, 'r'))
  	local s = assert(f:read('*a'))
  	f:close()
  	if raw then
        	return s
  	end
  	s = string.gsub(s, '^%s+', '')
  	s = string.gsub(s, '%s+$', '')
	s = string.gsub(s, '[\n\r]+', ' ')
   return s
end

function sensor_write(mac, handle, value)
  	-- write value addressed by handle(tag)
  	temp = 'sudo gatttool -b ' .. mac .. ' --char-write -a ' .. handle .. ' -n ' .. value
  	os.execute(temp)
end


function sensor_read(mac, handle)
	local ht, htt, lt, ltt
 	-- read values from sensor. values are returned in decimal (signed or unsigned), 
	-- in accordance to attribute table
  	local c = 'sudo gatttool -b ' .. mac .. ' --char-read -a ' .. handle
  	f =  os.capture(c,true)
	-- debug
	--  print(f)
  	lt, ht, ltt, htt = string.match(f, '(%x%x) (%x%x) (%x%x) (%x%x)')
  	s1 = ht .. lt
  	s2 = htt .. ltt
  	val1 = hex2num(s1,"signed")
  	val2 = hex2num(s2,"signed")
	--debug
	--  print(val1,val2)
  return val1, val2
end

function hex2num(h, switch)
        r = tonumber(h,16)
        if (switch == "signed") then
                if (r > 32767) then
                        r = r - 65536
                end
        end
   return r
end

function cal_read(mac, handle)

	local c0, c1, c2, c3, c4, c5, c6, c7
	-- read values from sensor. values are returned in decimal (sigend or unsigned), 
	-- in accordance to attribute table
	local c = 'sudo gatttool -b ' .. mac .. ' --char-read -a ' .. handle
  	local f =  os.capture(c,true)
	--debug
	-- print(f)
  l0, h0, l1, h1, l2, h2, l3, h3, l4, h4, l5, h5, l6, h6, l7, h7 = string.match(f, '(%x%x) (%x%x) (%x%x) (%x%x) (%x%x) (%x%x) (%x%x) (%x%x) (%x%x) (%x%x) (%x%x) (%x%x) (%x%x) (%x%x) (%x%x) (%x%x)')
  	c0 = hex2num(h0 .. l0,"no")
  	c1 = hex2num(h1 .. l1,"no")
  	c2 = hex2num(h2 .. l2,"no")
  	c3 = hex2num(h3 .. l3,"no")
  	c4 = hex2num(h4 .. l4,"signed")
  	c5 = hex2num(h5 .. l5,"signed")
  	c6 = hex2num(h6 .. l6,"signed")
  	c7 = hex2num(h7 .. l7,"signed")

	--debug
	--  print(c0 .. " " .. c1 .. " " .. c2 .. " " .. c3 .. " " .. c4 .. " " .. c5 .. " " .. c6 .. " " .. c7)

   return c0, c1, c2, c3, c4, c5, c6, c7
end


commandArray = {}

-------------data-------------------------------------
------------SENSORTAG BLE MAC ------------------------
	-- insert the your SensorTag MAC address
        blemac = 'B4:99:4C:64:30:B7'
	
--------------SENSOR SWITCHES ------------------------
        sensor_t = 1
        sensor_h = 1
        sensor_b = 1

--------------Virtual device ID number ------------------------
	-- get your virtual device ID and insert the correct vaules
        v_temp1 = 9
        v_target = 12
        v_temp2 = 10
        v_humidity = 14
        v_temp3 = 16
        v_baro = 15
        v_summa = 17

--------------Start with SensorTag measurement activation -----

--------------Thermometer sensor ------------------------------
        if sensor_t == 1 then
                -- temperature sensor: obtain ambience temperature and target temperature
                -- write handle and value
                tag = '0x29'
                val = '01'

		--write remote registry 
                sensor_write(blemac, tag, val)

        end

-----------------Humidity sensor ------------------------------
        if sensor_h == 1 then
                tag = '0x3f'
                val = '01'

		--write remote registry 
                sensor_write(blemac, tag, val)
        end

-----------------Barometer sensor ------------------------------
        if sensor_b == 1 then
                tag = '0x55'
                val = '02'

		--write remote registry 
                sensor_write(blemac, tag, val)

		--retrive sensor calibration values
                tag = '0x5b'
                c0, c1, c2, c3, c4, c5, c6, c7 =cal_read(blemac, tag)

		--write remote registry 
                tag = '0x55'
                val = '01'
                sensor_write(blemac, tag, val)
        end
----------------------measurement time-------------------------

        os.execute('sleep 0.5')


-------------------- mesurement reading part ------------------

----------- temperature sensor (ambient and target) -----------
        if sensor_t == 1 then
                -- read tag
                tag = '0x25'

                -- raw decimal values
                tt, ta = sensor_read(blemac, tag)

                -- calculation
                temp_amb_1 = ta / 128
                Tdie2 = temp_amb_1 + 273.15
                Vobj2 = tt * 0.00000015625

                -- calibration factor Typical values for S0 are between 5 × 10^(–14) and 7 × 10^(–14)
                S0 = 6.4e-14

                a1 = 1.75e-3
                a2 = -1.678e-5
                b0 = -2.94e-5
                b1 = -5.7e-7
                b2 = 4.63e-9
                d2 = 13.4
                Tref = 298.15
                S = S0*(1+a1*(Tdie2 - Tref)+a2 * math.pow((Tdie2 - Tref),2))
                Vos = b0 + b1*(Tdie2 - Tref) + b2 * math.pow((Tdie2 - Tref),2)
                fObj = (Vobj2 - Vos) + d2 * math.pow((Vobj2 - Vos),2)
                tObj = math.pow(math.pow(Tdie2, 4) + (fObj/S), 0.25)
                temp_obj = (tObj - 273.15)

----- format values for printout ------------------------------
                temp_amb_1 = string.format("%.2f",temp_amb_1)
                temp_obj = string.format("%.2f",temp_obj)

                commandArray[1] = {['UpdateDevice'] =  v_temp1 .. "|0|" .. temp_amb_1}
                commandArray[2] = {['UpdateDevice'] =  v_target .. "|0|" .. temp_obj}

        end

------Humidity sensor(ambient temp & relative humidity)-------

        if sensor_h == 1 then

                -- read tag
                tag = '0x3b'

                -- raw decimal values
                tt, ta = sensor_read(blemac, tag)

                -- calculation
                temp_amb_2 = -46.85 + 175.72/65536 * tt
                rel_humid = -6.0 + 125.0/65536 * ta

----- format values for printout ------------------------------
                temp_amb_2 = string.format("%.2f",temp_amb_2)
                rel_humid = string.format("%.2f",rel_humid)


                commandArray[3] = {['UpdateDevice'] =  v_temp2 .. "|0|" .. temp_amb_2}
                commandArray[4] = {['UpdateDevice'] =  v_humidity .. "|" .. rel_humid .. "|" .. "0"}

        end

--------------barometer sensor (temperature & pressure)--------

        if sensor_b == 1 then

		-- read tag
                tag = '0x51'

		-- raw decimal values 
                tt, ta = sensor_read(blemac, tag)

		-- barometer values shall converted to 
		-- unsigned interger 
                -- two's complement
                if ta < 0 then
                        ta = ta + 65536
                end

                -- calculation
                temp_amb_3 = ((c0 * tt) / 2^24) + (c1 / 2^10)
                sensitivity = (c2 + ((c3 * tt) / 2^17) + ((c4 * tt^2) / 2^34))
                offset = (c5 * 2^14) + ((c6 * tt) / 2^3) + ((c7 * tt^2) / 2^19)
                press_hPa = ((sensitivity * ta + offset) / 2^14) / 100

----- format values for printout ------------------------------
                temp_amb_3 = string.format("%.2f",temp_amb_3)
                press_hPa = string.format("%.1f",press_hPa)


                commandArray[5] = {['UpdateDevice'] =  v_temp3 .. "|0|" .. temp_amb_3}

		-- combo temp, humidity and barometer 
		-- virtual device 
                commandArray[6] = {['UpdateDevice'] =  v_summa .. "|0|" .. temp_amb_3 .. ";" ..rel_humid .. ";0;" .. press_hPa .. ";0"}
        end


return commandArray