Skip to content
This repository has been archived by the owner on Feb 10, 2021. It is now read-only.

Commit

Permalink
Merge pull request #231 from Azure/BLEConfig
Browse files Browse the repository at this point in the history
Ble config merge into master
  • Loading branch information
Olivier Bloch committed Feb 5, 2016
2 parents fb3ea5b + de6d3a6 commit 5b55f29
Show file tree
Hide file tree
Showing 8 changed files with 337 additions and 296 deletions.
171 changes: 84 additions & 87 deletions Devices/GatewayConnectedDevices/BLEMoisture/BLEMoistureSensor.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
'''
'''
Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
The MIT License (MIT)
Expand Down Expand Up @@ -55,92 +55,89 @@
ADV_SCAN_RSP=0x04

def eventHandler(macAddress, value):
f(macAddress,value)
f(macAddress,value)

class BLEMoistureSensor:

sock = None
callback = None
dev_id = 0

def __init__(self) :
try:
self.sock = bluez.hci_open_dev(self.dev_id)
old_filter = self.sock.getsockopt( bluez.SOL_HCI, bluez.HCI_FILTER, 14)
enable = 1
cmd_pkt = struct.pack("<BB", enable, 0x00)
bluez.hci_send_cmd(self.sock, OGF_LE_CTL, OCF_LE_SET_SCAN_ENABLE, cmd_pkt)

except:
print "error accessing blue tooth device..."
sys.exit(1)

def printpacket(self, pkt):
print "in printpacket"
for c in pkt:
sys.stdout.write("%02x " % struct.unpack("B",c)[0])

def packed_bdaddr_to_string(self, bdaddr_packed):
return ''.join('%02x'%i for i in struct.unpack("<BBBBBB", bdaddr_packed[::-1]))


# func( macAddress, value )
def setSensorDataAvailableEvent(self, func):
self.callback = func

def Listen(self):
try:
old_filter = self.sock.getsockopt( bluez.SOL_HCI, bluez.HCI_FILTER, 14)

# perform a device inquiry on blue tooth device #0
# The inquiry should last 8 * 1.28 = 10.24 seconds
# before the inquiry is performed, bluez should flush its cache of
# previously discovered devices
flt = bluez.hci_filter_new()
bluez.hci_filter_all_events(flt)
bluez.hci_filter_set_ptype(flt, bluez.HCI_EVENT_PKT)
self.sock.setsockopt( bluez.SOL_HCI, bluez.HCI_FILTER, flt )
while True:
pkt = self.sock.recv(255)
ptype, event, plen = struct.unpack("BBB", pkt[:3])

if event == bluez.EVT_INQUIRY_RESULT_WITH_RSSI:
i =0
elif event == bluez.EVT_NUM_COMP_PKTS:
i =0
elif event == bluez.EVT_DISCONN_COMPLETE:
i =0
elif event == LE_META_EVENT:
subevent, = struct.unpack("B", pkt[3])
pkt = pkt[4:]
if subevent == EVT_LE_CONN_COMPLETE:
le_handle_connection_complete(pkt)
elif subevent == EVT_LE_ADVERTISING_REPORT:
#print "advertising report"
num_reports = struct.unpack("B", pkt[0])[0]
report_pkt_offset = 0
for i in range(0, num_reports):
if (DEBUG == True):
print "-------------"
print "\t", "full packet: ", self.printpacket(pkt)
print "\t", "MAC address: ", self.packed_bdaddr_to_string(pkt[report_pkt_offset + 3:report_pkt_offset + 9])
# build the return string
id = pkt[report_pkt_offset +12: report_pkt_offset +26]
if (DEBUG == True):
print "\t", "id: ", id
if (id == 'MSOT_BLE_Demo:'):
# MAC address
macAddress = self.packed_bdaddr_to_string(pkt[report_pkt_offset + 3:report_pkt_offset + 9])
# string representation of Water Volume Content (unit-less) floating point value
value = pkt[report_pkt_offset + 26: report_pkt_offset + 36]
if (DEBUG == True):
print "\t", "address=", macAddress, " value=", value
if( self.callback != None ):
print "calling event handler"
self.callback( macAddress, value )
except:
self.sock.setsockopt( bluez.SOL_HCI, bluez.HCI_FILTER, old_filter )
print "error in BLE Listen loop"
sys.exit(1)


sock = None
callback = None
dev_id = 0

def __init__(self) :
try:
self.sock = bluez.hci_open_dev(self.dev_id)
old_filter = self.sock.getsockopt( bluez.SOL_HCI, bluez.HCI_FILTER, 14)
enable = 1
cmd_pkt = struct.pack("<BB", enable, 0x00)
bluez.hci_send_cmd(self.sock, OGF_LE_CTL, OCF_LE_SET_SCAN_ENABLE, cmd_pkt)

except:
print "error accessing blue tooth device..."
sys.exit(1)

def printpacket(self, pkt):
print "in printpacket"
for c in pkt:
sys.stdout.write("%02x " % struct.unpack("B",c)[0])

def packed_bdaddr_to_string(self, bdaddr_packed):
return ''.join('%02x'%i for i in struct.unpack("<BBBBBB", bdaddr_packed[::-1]))

# func( macAddress, value )
def setSensorDataAvailableEvent(self, func):
self.callback = func

def Listen(self):
try:
old_filter = self.sock.getsockopt( bluez.SOL_HCI, bluez.HCI_FILTER, 14)

# perform a device inquiry on blue tooth device #0
# The inquiry should last 8 * 1.28 = 10.24 seconds
# before the inquiry is performed, bluez should flush its cache of
# previously discovered devices
flt = bluez.hci_filter_new()
bluez.hci_filter_all_events(flt)
bluez.hci_filter_set_ptype(flt, bluez.HCI_EVENT_PKT)
self.sock.setsockopt( bluez.SOL_HCI, bluez.HCI_FILTER, flt )
while True:
pkt = self.sock.recv(255)
ptype, event, plen = struct.unpack("BBB", pkt[:3])

if event == bluez.EVT_INQUIRY_RESULT_WITH_RSSI:
i =0
elif event == bluez.EVT_NUM_COMP_PKTS:
i =0
elif event == bluez.EVT_DISCONN_COMPLETE:
i =0
elif event == LE_META_EVENT:
subevent, = struct.unpack("B", pkt[3])
pkt = pkt[4:]
if subevent == EVT_LE_CONN_COMPLETE:
le_handle_connection_complete(pkt)
elif subevent == EVT_LE_ADVERTISING_REPORT:
#print "advertising report"
num_reports = struct.unpack("B", pkt[0])[0]
report_pkt_offset = 0
for i in range(0, num_reports):
if (DEBUG == True):
print "-------------"
print "\t", "full packet: ", self.printpacket(pkt)
print "\t", "MAC address: ", self.packed_bdaddr_to_string(pkt[report_pkt_offset + 3:report_pkt_offset + 9])
# build the return string
id = pkt[report_pkt_offset +12: report_pkt_offset +26]
if (DEBUG == True):
print "\t", "id: ", id
if (id == 'MSOT_BLE_Demo:'):
# MAC address
macAddress = self.packed_bdaddr_to_string(pkt[report_pkt_offset + 3:report_pkt_offset + 9])
# string representation of Water Volume Content (unit-less) floating point value
value = pkt[report_pkt_offset + 26: report_pkt_offset + 36]
if (DEBUG == True):
print "\t", "address=", macAddress, " value=", value
if( self.callback != None ):
print "calling event handler"
self.callback( macAddress, value )
except:
self.sock.setsockopt( bluez.SOL_HCI, bluez.HCI_FILTER, old_filter )
print "error in BLE Listen loop"
sys.exit(1)
4 changes: 4 additions & 0 deletions Devices/GatewayConnectedDevices/BLEMoisture/DeviceConfig.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
MACAddress,DisplayName,Organization,Location,MeasureName,UnitsOfMeasure
1,test,now,here,unknown,improbable
2,foo,bar,what,that,impossible
*,none,none,none,none,none
171 changes: 105 additions & 66 deletions Devices/GatewayConnectedDevices/BLEMoisture/SensorAgent.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
'''
'''
Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
The MIT License (MIT)
Expand All @@ -24,79 +24,118 @@
import time
import datetime
import re

from BLEMoistureSensor import BLEMoistureSensor
import csv
import sys

Debug = False

Org = "Your organization";
Disp = "Sensor display name" # will be the label for the curve on the chart
GUID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" # ensures all the data from this sensor appears on the same chart. You can use the Tools/Create GUID in Visual Studio to create.
# The last 6 bytes will be replaced with the mac address of the BLE module that is transmitting the moisture data.
Locn = "Sensor location";
IronPythonPlatform = 'cli'

Vendor = 0xfffe # Vendor ID for our custom device
Product = 0xfffe # Product ID for our custom device

HOST = '127.0.0.1'
PORT = 5002
if sys.platform != IronPythonPlatform:
from BLEMoistureSensor import BLEMoistureSensor

CONNECT_RETRY_INTERVAL = 2
EXCEPTION_THRESHOLD = 3
SEND_INTERVAL = 5
EXCEPTION_THRESHOLD = 3
SEND_INTERVAL = 5

s = None

def processSensorData( macAddress, value ) :
global s
timeStr = datetime.datetime.utcnow().isoformat()

# replace last group of digits with mac address of BLE sensor board
deviceID = GUID
deviceID = deviceID[:24] + macAddress

JSONString = "{"
JSONString += "\"value\":" + value
JSONString += ",\"guid\":\"" + deviceID
JSONString += "\",\"organization\":\"" + Org
JSONString += "\",\"displayname\":\"" + Disp
JSONString += "\",\"unitofmeasure\":\"" + "vol/vol"
JSONString += "\",\"measurename\":\"" + "WaterContent"
JSONString += "\",\"location\":\"" + Locn
JSONString += "\",\"timecreated\":\"" + timeStr + "\""
JSONString += "}"

if Debug == True:
print "JSONString=", JSONString

if s != None :
s.send("<" + JSONString + ">"); # sends to gateway over socket interface

deviceConfig = {}
sensorAgentConfig = None

def processSensorData(macAddress, value) :
global s
global deviceConfig
global sensorAgentConfig
timeStr = datetime.datetime.utcnow().isoformat()

macAddressRecognized = False

# replace last group of digits with mac address of BLE sensor board
deviceID = sensorAgentConfig["GUID"]
deviceID = deviceID[:24] + macAddress
JSONString = "{"
JSONString += "\"value\": %s" % value
JSONString += ",\"guid\":\"" + deviceID

macAddressKey = macAddress
displayName = ""
if macAddress in deviceConfig:
macAddressRecognized = True
displayName = deviceConfig[macAddressKey]["DisplayName"]
elif '*' in deviceConfig:
macAddressKey = '*'
macAddressRecognized = True
displayName = macAddress

if macAddressRecognized == True:
JSONString += "\",\"organization\":\"" + deviceConfig[macAddressKey]["Organization"]
JSONString += "\",\"displayname\":\"" + displayName
JSONString += "\",\"unitofmeasure\":\"" + deviceConfig[macAddressKey]["UnitsOfMeasure"]
JSONString += "\",\"measurename\":\"" + deviceConfig[macAddressKey]["MeasureName"]
JSONString += "\",\"location\":\"" + deviceConfig[macAddressKey]["Location"]
JSONString += "\",\"timecreated\":\"" + timeStr + "\""
JSONString += "}"

if Debug == True:
print "JSONString=", JSONString
if s != None :
# send JSON string to gateway over socket interface
s.send("<" + JSONString + ">")

def main() :
try:
global s
# setup moisture sensor
moistureSensor = BLEMoistureSensor()
moistureSensor.setSensorDataAvailableEvent(processSensorData)

# setup server socket
if Debug == False :
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print("Socket created.")
while True:
try:
s.connect((HOST, PORT));
break;
except socket.error as msg:
print("Socket connection failed. Error Code : " + str(msg[0]) + " Message " + msg[1])
time.sleep(CONNECT_RETRY_INTERVAL)
print ("Socket connection succeeded.")

# this will listen forever for advertising events and call processSensorData() when data arrives
moistureSensor.Listen();

except KeyboardInterrupt:
print("Continuous polling stopped")

global s
global deviceConfig
global sensorAgentConfig

# parse SensorAgent configuration CSV file
try:
with open('SensorAgentConfig.csv') as sensorAgentConfigFile:
sensorAgentConfigSource = csv.DictReader(sensorAgentConfigFile)
for row in sensorAgentConfigSource :
sensorAgentConfig = row
# we only care about first row in config file
break;
except:
print "Error reading config file. Please correct before continuing."
sys.exit()


# parse device configuration (BLE device) CSV file
try:
with open('DeviceConfig.csv') as deviceConfigFile:
deviceConfigSource = csv.DictReader(deviceConfigFile)
for row in deviceConfigSource:
deviceConfig[row["MACAddress"]] = row
except:
print "Error reading config file. Please correct before continuing."
sys.exit()

try:
# setup moisture sensor
if sys.platform != 'cli':
moistureSensor = BLEMoistureSensor()
moistureSensor.setSensorDataAvailableEvent(processSensorData)

# setup server socket
if Debug == False :
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print "Socket created."
while True:
try:
s.connect((sensorAgentConfig["Host"], int(sensorAgentConfig["Port"])))
break
except socket.error as msg:
print "Socket connection failed. Error Code : " + str(msg[0]) + " Message " + msg[1]
time.sleep(CONNECT_RETRY_INTERVAL)
print "Socket connection succeeded."

# this will listen forever for advertising events and call
# processSensorData() when data arrives
if sys.platform != IronPythonPlatform:
moistureSensor.Listen()

except KeyboardInterrupt:
print "Continuous polling stopped"

if __name__ == '__main__':
main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
GUID,Host,Port
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,127.0.0.1,5002
2 changes: 2 additions & 0 deletions Devices/GatewayConnectedDevices/BLEMoisture/deploy_next.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ echo editing line endings for Pi
echo Copying file that starts up python script to read hydrology sensors and format as JSON
%PSCP_CMD% SensorAgent.py %rpi_usr%@%rpi_ip%:%Staging%/
%PSCP_CMD% BLEMoistureSensor.py %rpi_usr%@%rpi_ip%:%Staging%/
%PSCP_CMD% SensorAgentConfig.csv %rpi_usr%@%rpi_ip%:%Staging%/
%PSCP_CMD% DeviceConfig.csv %rpi_usr%@%rpi_ip%:%Staging%/
%PSCP_CMD% Modified\autorun2.sh %rpi_usr%@%rpi_ip%:%Staging%/

echo Marking autorun2.sh as executable
Expand Down
Loading

0 comments on commit 5b55f29

Please sign in to comment.