forked from rkoshak/sensorReporter
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbluetoothScanner.py
More file actions
144 lines (119 loc) · 4.99 KB
/
bluetoothScanner.py
File metadata and controls
144 lines (119 loc) · 4.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
"""
Script: bluetoothScanner.py
Author: Rich Koshak / Lenny Shirley <http://www.lennysh.com> / Sascha Sambale
Date: June 7th, 2016
Purpose: Scans for a Bluetooth device with a given address and publishes whether or not the device is present using RSSI figures, or lookup function.
Credit From: https://github.com/blakeman399/Bluetooth-Proximity-Light/blob/master/https/github.com/blakeman399/Bluetooth-Proximity-Light.py
"""
import array
import bluetooth
import bluetooth._bluetooth as bt
import fcntl
import struct
debug = 0
"""Either use 'RSSI' mode, or 'LOOKUP' mode. RSSI is more reliable."""
mode = "RSSI"
# mode = "LOOKUP"
class BtSensor:
"""Represents a Bluetooth device"""
def __init__(self, section, config, publish, logger):
"""Finds whether the BT device is close and publishes its current state"""
self.logger = logger
self.name = config.get(section, "Name")
self.address = config.get(section, "Address")
self.destination = config.get(section, "Destination")
self.publish = publish
self.poll = config.getfloat(section, "Poll")
self.logger.info(
"----------Configuring BluetoothSensor: Name = %s Address = %s Destination = %s", self.name,
self.address, self.destination)
# assume phone is initially far away
# self.far = True
self.far_count = 0
self.near_count = 0
self.rssi = None
self.state = "OFF"
self.publish_state()
def get_presence(self):
"""Detects whether the device is near by or not using lookup_name"""
result = bluetooth.lookup_name(self.address, timeout=25)
if result is not None:
return "ON"
else:
return "OFF"
def get_rssi(self):
"""Detects whether the device is near by or not using RSSI"""
addr = self.address
# Open hci socket
hci_sock = bt.hci_open_dev()
hci_fd = hci_sock.fileno()
# Connect to device (to whatever you like)
bt_sock = bluetooth.BluetoothSocket(bluetooth.L2CAP)
bt_sock.settimeout(10)
bt_sock.connect_ex((addr, 1)) # PSM 1 - Service Discovery
try:
# Get ConnInfo
reqstr = struct.pack("6sB17s", bt.str2ba(addr), bt.ACL_LINK, "\0" * 17)
request = array.array("c", reqstr)
fcntl.ioctl(hci_fd, bt.HCIGETCONNINFO, request, 1)
handle = struct.unpack("8xH14x", request.tostring())[0]
# Get RSSI
cmd_pkt = struct.pack('H', handle)
rssi = bt.hci_send_req(hci_sock, bt.OGF_STATUS_PARAM,
bt.OCF_READ_RSSI, bt.EVT_CMD_COMPLETE, 4, cmd_pkt)
rssi = struct.unpack('b', rssi[3])[0]
# Close sockets
bt_sock.close()
hci_sock.close()
return rssi
except Exception, e:
# self.logger.error("<Bluetooth> (getRSSI) %s" % (repr(e)))
return None
def check_state(self):
"""Detects and publishes any state change"""
if mode == "RSSI":
value = self.state
self.rssi = self.get_rssi()
if self.rssi is None:
if self.far_count < 3:
self.logger.info("Signal lost - will wait just to be sure.")
self.far_count += 1
self.near_count -= 1
if self.near_count < 0:
self.near_count = 0
if self.far_count > 15:
self.far_count = 15
elif self.rssi > 1:
if self.near_count < 10:
self.logger.info(
"Got signal from " + self.name + ", waiting for stronger one: " + str(
self.near_count * 10) + "%.")
self.far_count -= 1
self.near_count += 1
if self.far_count < 0:
self.far_count = 0
if self.near_count > 10:
self.near_count = 10
if self.near_count > self.far_count and self.near_count >= 10:
value = "ON"
elif self.far_count > self.near_count and self.far_count > 3:
value = "OFF"
else:
value = self.state
self.logger.debug(
"Name "+self.name+" Destination " + self.destination + " far count = " + str(
self.far_count) + " near count = " + str(
self.near_count) + " RSSI = " + str(self.rssi))
elif mode == "LOOKUP":
value = self.get_presence()
else:
msg = "Invalid 'mode' specified in 'bluetoothScanner.py' !"
print msg
self.logger.error(msg)
return
if value != self.state:
self.state = value
self.publish_state()
def publish_state(self):
"""Publishes the current state"""
self.publish(self.state, self.destination)