TI-Nspire & SensorTag / 気象関連のデータを全部一度に取り出す



The following script will try to extract weather data from CC2650 SensorTag.
.lua

require "bleCentral"

local bleState        = ""
local peripheralState = ""
local myPeripheral    = nil
local peripheralName  = ""

-- Temperature
TMP007 = {
   name       = "TMP007" ,
   dataUUID   = "F000AA01-0451-4000-B000-000000000000" ,
   confUUID   = "F000AA02-0451-4000-B000-000000000000" ,
   loData     = nil ,
   loDataUnit = "°C (ir)" ,
   hiData     = nil ,
   hiDataUnit = "°C (die)" ,
   convert    = function(value)
                   local loRaw, hiRaw = string.unpack("s16s16", value) -- IR[0:7], IR[8:15], DIE[0:7], DIE[8:15]
                   local irTemp  = tonumber(loRaw)/128
                   local dieTemp = tonumber(hiRaw)/128
                   return irTemp, dieTemp
                end ,
}

-- Humidity
HDC1000 = {
   name       = "HDC1000" ,
   dataUUID   = "F000AA21-0451-4000-B000-000000000000" ,
   confUUID   = "F000AA22-0451-4000-B000-000000000000" ,
   loData     = nil ,
   loDataUnit = "°C" ,
   hiData     = nil ,
   hiDataUnit = "%RH" ,
   convert    = function(value)
                   local loRaw, hiRaw = string.unpack("u16u16", value) -- Temp[0:7], Temp[8:15], Hum[0:7], Hum[8:15]
                   local temp     = (tonumber(loRaw) / 65536) * 165 - 40
                   local humidity = (tonumber(hiRaw) / 65536) * 100
                   return temp, humidity 
                end ,
}

-- Pressure
BMP280 = {
   name       = "BMP280" ,
   dataUUID   = "F000AA41-0451-4000-B000-000000000000" ,
   confUUID   = "F000AA42-0451-4000-B000-000000000000" ,
   loData     = nil ,
   loDataUnit = "°C" ,
   hiData     = nil ,
   hiDataUnit = "hPa" ,
   convert    = function(value)
                   local loRaw, hiRaw = string.unpack("s24u24", value) -- Temp[0:7], Temp[8:15], Temp[16:23], Press[0:7], Press[8:15], Press[16:23]
                   local temp
                   if loRaw > 0 then
                      temp = tonumber(loRaw) / 100
                   else
                      temp = -(tonumber(loRaw) + 16777216) / 100 -- 16777216 = 2^24
                   end
                   local pressure = tonumber(hiRaw) / 100
                   return temp, pressure
                end ,
}

-- Illumination
OPT3001 = {
   name       = "OPT3001" ,
   dataUUID   = "F000AA71-0451-4000-B000-000000000000" ,
   confUUID   = "F000AA72-0451-4000-B000-000000000000" ,
   loData     = nil ,
   loDataUnit = "none" ,
   hiData     = nil ,
   hiDataUnit = "lux" ,
   convert    = function(value)
                   local raw = string.unpack("u16", value) -- LightLSB:LightMSB
                   local exponent = math.evalStr("shift(("..raw.." and 0hF000), -12)")
                   local mantissa = math.evalStr("("..raw.." and 0h0FFF)")
                   return 0, mantissa * (0.01 * 2^exponent)
                end ,
}

sensorsList = {TMP007, HDC1000, BMP280, OPT3001}

function on.resize()
   W, H = platform.window:width(), platform.window:height()
   leftMargin = W/100
   fontSize   = W/23
   lineSpace  = H/8
   platform.window:invalidate()
end
function on.construction()
   refreshMenu()
   ble.addStateListener(stateListener)
end
function on.paint(gc)
   gc:setFont("sansserif", "r", fontSize)
   gc:drawString(bleState        , leftMargin, lineSpace * 0)
   gc:drawString(peripheralName  , leftMargin, lineSpace * 1)
   gc:drawString(peripheralState , leftMargin, lineSpace * 2)

   for i, sensor in ipairs(sensorsList) do
      if sensor.loData or sensor.hiData then
         gc:drawString(
            string.format(
               "%s :  %.1f %s ,  %.1f %s", 
               sensor.name,  sensor.hiData,  sensor.hiDataUnit,  sensor.loData,  sensor.loDataUnit
            ),
            leftMargin,  lineSpace * (i + 2)
         )
      end
   end

end

------------------------------
-- Menu, Keyboard and Mouse --
------------------------------
function refreshMenu()
   Menu = {
      {"Controls",
         {"Scan and Connect", function() peripheralOn()  end},
         {"Disconnect"      , function() peripheralOff() end},
      }
   }
   toolpalette.register(Menu)
end

--------------------------
-- Define state listner --
--------------------------
function stateListener(state)
   if state == "on" then
      peripheralOn()
   end 
   bleState = "BLE: "..state
   platform.window:invalidate()
end

----------------------------
-- Start or stop scanning --
----------------------------
function peripheralOn()
   if peripheralState ~= "connected" then
      bleCentral.startScanning(scanner)
   end 
   platform.window:invalidate()
end
function peripheralOff()
   bleCentral.stopScanning()
   if myPeripheral then
      myPeripheral:disconnect()
   end
   peripheralName = "" 
   platform.window:invalidate()
end

--------------------
-- Define scanner --
--------------------
function scanner(peripheral)
   local name = peripheral:getName() or ""
   if peripheral and name:find("SensorTag") then
      myPeripheral   = peripheral
      peripheralName = name
      peripheral:connect(connector) 
   end
   platform.window:invalidate()
end

----------------------
-- Define connector --
----------------------
function connector(peripheral, event)
   local name = peripheral:getName() or ""
   if event == bleCentral.CONNECTED and name:find("SensorTag") then
      bleCentral.stopScanning()
      myPeripheral    = peripheral
      peripheralName  = name
      peripheral:discoverServices(servicesDiscoverer)
   elseif event == bleCentral.DISCONNECTED then 
      myPeripheral    = nil
      peripheralName  = ""
   end
   peripheralState = peripheral:getState()
   platform.window:invalidate()
end

--------------------------------
-- Define services discoverer --
--------------------------------
function servicesDiscoverer(peripheral)
   if peripheral:getState() == bleCentral.CONNECTED then
      local servicesList = peripheral:getServices()
      for _, v in ipairs(servicesList) do
         v:discoverCharacteristics(characteristicsDiscoverer)
      end
   end
   platform.window:invalidate()
end

---------------------------------------
-- Define characteristics discoverer --
---------------------------------------
function characteristicsDiscoverer(service)
   local characteristicsList = service:getCharacteristics()
   for _, characteristic in ipairs(characteristicsList) do
      local UUID = characteristic:getUUID() 


      for _, sensor in ipairs(sensorsList) do
         if UUID == sensor.dataUUID then
            characteristic:setValueUpdateListener(valueUpdateListener)
            characteristic:setNotify(true)
         elseif UUID == sensor.confUUID then
            -- characteristic:setWriteCompleteListener(valueUpdateListener)
            characteristic:write(string.uchar(0x01), true)
         end
      end


   end
end

----------------------------------
-- Define value-update listener --
----------------------------------
function valueUpdateListener(characteristic)
   local UUID = characteristic:getUUID()


   for _, sensor in ipairs(sensorsList) do
      if UUID == sensor.dataUUID then
         local value = characteristic:getValue()
         if value then
            sensor.loData, sensor.hiData = sensor.convert(value)
         end
      end
   end


   platform.window:invalidate()
end

References: