SF30 Controller Bluez Programming - python

Bluez Question:
I have a Raspberry Pi Z W, an 8bitdo SF30 bluetooth controller and a robot my employer mass produces. I am looking to control the robot from the RPI through the remote.
I have the RPi connecting to the controller using bluetoothctl, and I can see the messages from the controller through btmon (bluetooth monitor).
It becomes obvious that the four "80" values below correspond to the two joysticks at their mid points.
> ACL Data RX: Handle 11 flags 0x02 dlen 15 #30 [hci0] 2.555574
Channel: 65 len 11 [PSM 0 mode Basic (0x00)] {chan 65535}
a1 03 0f 80 80 12 31 00 00 00 00 ......1....
> ACL Data RX: Handle 11 flags 0x02 dlen 15 #31 [hci0] 2.587293
Channel: 65 len 11 [PSM 0 mode Basic (0x00)] {chan 65535}
a1 03 0f 80 80 27 4b 00 00 00 00 .....'K....
> ACL Data RX: Handle 11 flags 0x02 dlen 15 #32 [hci0] 2.613543
Channel: 65 len 11 [PSM 0 mode Basic (0x00)] {chan 65535}
a1 03 0f 80 80 61 7b 00 00 00 00 .....a{....
> ACL Data RX: Handle 11 flags 0x02 dlen 15 #33 [hci0] 2.615552
Channel: 65 len 11 [PSM 0 mode Basic (0x00)] {chan 65535}
a1 03 0f 80 80 80 80 00 00 00 00 ...........
> ACL Data RX: Handle 11 flags 0x02 dlen 15 #34 [hci0] 74.653567
Channel: 65 len 11 [PSM 0 mode Basic (0x00)] {chan 65535}
a1 03 0f 80 80 80 80 00 00 00 08 ...........
I have also been reading in data from the two resulting /dev/input/ files (/dev/input/js0 and /dev/input/event0) in python using format LLHHQ.
I thought that the same data from btmon (which is easy to interpret) would be represented in the Q section of that format (the last number below).
(470898350, 155732, 22190, 7185, 16919435)
(470898350, 160124, 22190, 7185, 16916057)
(470898380, 162488, 22220, 7185, 163502)
(470898380, 16915382, 22260, 7185, 16910652)
(470898420, 16908288, 22290, 7185, 161137)
(470898450, 16971797, 22300, 7185, 155732)
(470898460, 16966392, 22330, 7185, 154043)
(470898490, 16966054, 22340, 7185, 147287)
(470898500, 16967405, 22340, 7185, 131072)
(470898500, 16908288, 22740, 7185, 151060481)
(470899070, 151060480, 22970, 7185, 134283265)
(470899320, 134283264, 23200, 7185, 117506049)
(470899550, 117506048, 23420, 7185, 100728833)
(470899750, 100728832, 23590, 7185, 117506049)
(470899910, 117506048, 23930, 7185, 134283265)
(470900310, 134283264, 25110, 7185, 100728833)
(470901380, 117506049, 25250, 7185, 134283265)
(470901490, 100728832, 25390, 7185, 117506048)
(470901710, 134283264, 25580, 7185, 100728833)
(470901750, 117506049, 25720, 7185, 117506048)
(470901940, 134283265, 25810, 7185, 100728832)
(470902160, 100728833, 26070, 7185, 134283264)
(470902400, 100728832, 26690, 7185, 134283265)
(470903070, 134283264, 27130, 7185, 151060481)
(470903430, 151060480, 27360, 7185, 100728833)
However these outputs don't appear to correspond when read into binary, for example the two joysticks seem to change the same bits.
The basic of my question is how do I get the same data which is read in the btmon in a bluez-based code.
This is the python code I am using at the moment.
f = open( "/dev/input/js0", "rb" ); # Open the file in the read-binary mode
EVENT_SIZE = struct.calcsize("LLHHQ")
while 1:
data = f.read(EVENT_SIZE)
unpacked_data = struct.unpack('llHHQ',data)
# print("Length:" + str(len(unpacked_data)))
# print(unpacked_data)
remote_data = unpacked_data[4]
print(format(remote_data, '064b'))

It might be helpful to use a library like evdev as it will do much of the heavy lifting for you.
Example of using this might be:
from time import sleep
from pydbus import SystemBus
import evdev
# For testing
# python3 -m evdev.evtest
class Controller:
def __init__(self, adapter_int=0):
adapter_path = '/org/bluez/hci{}'.format(adapter_int)
self.dbus = SystemBus()
self.adapter = self.dbus.get('org.bluez', adapter_path)
# Use bluetoothctl to find out what the path is for your controller
self.controller = self.dbus.get('org.bluez', '/org/bluez/hci0/dev_DC_0C_2D_20_DA_E8')
print('Waiting for connection from DC:0C:2D:20:DA:E8')
# self.controller.Discoverable = True
while not self.controller.Connected:
sleep(1)
print('Connected')
sleep(6)
# https://python-evdev.readthedocs.io/en/latest/tutorial.html to get path of your controller
self.device = evdev.InputDevice('/dev/input/event2')
self.max_value = 0
self.min_value = 255
self.max_throttle = 1
self.min_throttle = -1
self.right_steering = 1
self.left_steering = -1
def map_throttle(self, value):
input_range = self.max_value - self.min_value
output_range = self.max_throttle - self.min_throttle
input_percentage = (value - self.min_value) / input_range
output_value = (output_range * input_percentage) + self.min_throttle
return round(output_value, 2)
def map_steering(self, value):
input_range = self.max_value - self.min_value
output_range = self.right_steering - self.left_steering
input_percentage = (value - self.min_value) / input_range
output_value = (output_range * input_percentage) + self.left_steering
return round(output_value, 2)
def get_events(self):
for event in self.device.read_loop():
ly = None
rx = None
btn = None
if event.type == evdev.ecodes.EV_ABS:
if event.code == 1:
# print('Left:', event.value)
ly = self.map_throttle(event.value)
if event.code == 3:
# print('Right:', event.value)
rx = self.map_steering(event.value)
if event.type == evdev.ecodes.EV_KEY:
if event.code == evdev.ecodes.BTN_SOUTH and event.value == 0:
btn = 'BTN_SOUTH'
elif event.code == evdev.ecodes.BTN_WEST and event.value == 0:
btn = 'BTN_WEST'
elif event.code == evdev.ecodes.BTN_NORTH and event.value == 0:
btn = 'BTN_NORTH'
elif event.code == evdev.ecodes.BTN_EAST and event.value == 0:
btn = 'BTN_EAST'
yield ly, rx, btn
if __name__ == '__main__':
ctrl = Controller()
for speed, steer, action in ctrl.get_events():
print('Speed: {}, Steer: {}, Button: {}'.format(speed, steer, action))
If you wanted to go a little higher level, then a library like https://github.com/ApproxEng/approxeng.input is a popular one.

Related

TypeError: slice indices must be integers or None or have an __index__ method error in scraping a help page

I created python script to scrape facebook help page. I wanted to scrape cms_object_id, cmsID, name. so these values are in a script tag then firstly tried to find all <script> tags then tried to iterate over this and then there is __bbox inside the tags which contains the values wanted to scrape.
so this is my script:
import json
import requests
import bs4
from Essentials import Static
class CmsIDs:
def GetIDs():
# cont = requests.get(""https://www.facebook.com:443/help"", headers=Static.headers) # syntax error
cont = requests.get("https://www.facebook.com:443/help", headers=Static.headers)
soup = bs4.BeautifulSoup(cont.content, "html5lib")
text = soup.find_all("script")
start = ""
txtstr = ""
for i in range(len(text)):
mystr = text[i]
# mystr = text[i]
print("this is: ", mystr.find('__bbox":'))
if text[i].get_text().find('__bbox":') != -1:
# print(i, text[i].get_text())
txtstr += text[i].get_text()
start = text[i].get_text().find('__bbox":') + len('__bbox":')
print('start:', start)
count = 0
for end, char in enumerate(txtstr[start:], start):
if char == '{':
count += 1
if char == '}':
count -= 1
if count == 0:
break
print('end:', end)
# --- convert JSON string to Python structure (dict/list) ---
data = json.loads(txtstr[start:end+1])
# pp.pprint(data)
print('--- search ---')
CmsIDs.search(data)
# --- use recursion to find all 'cms_object_id', 'cmsID', 'name' ---
def search(data):
if isinstance(data, dict):
found = False
if 'cms_object_id' in data:
print('cms_object_id', data['cms_object_id'])
found = True
if 'cmsID' in data:
print('cmsID', data['cmsID'])
found = True
if 'name' in data:
print('name', data['name'])
found = True
if found:
print('---')
for val in data.values():
CmsIDs.search(val)
if isinstance(data, list):
for val in data:
CmsIDs.search(val)
if __name__ == '__main__':
CmsIDs.GetIDs()
the page contains cms_object_id, cmsID, name. so wanted to scrape all these 3 values but I am getting an error:
for end, char in enumerate(txtstr[start:], start):
TypeError: slice indices must be integers or None or have an __index__ method
so how can I solve this error and reach ultimate goal?
Note: Since I'm unfamiliar with and failed to install Essentials, and also because ""https://www.facebook.com:443/help"" raises a syntax error (there should only be one quote on each side of the string), I changed the requests line in my code.
cont = requests.get('https://www.facebook.com:443/help', headers={'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9'})
TypeError: slice indices must be integers or None or have an __index__ method
You've initiated start as a string [start = ""] and it needs to be an integer. Unless the if text[i].get_text().find('__bbox":') != -1.... block is entered, start remains a string.
if you just want to not get this error, you could just exit the program if start hasn't been updated [indicating that __bbox": wasn't found in any of the script tags].
print('start:', start)
if start == "":
print('{__bbox":} not found')
return
count = 0
But that still leaves the problem of __bbox": not being found; I'm not sure why, but the issue is resolved for me if I don't use the html5lib parser - just changing to BeautifulSoup(cont.content) resolved this issue.
# soup = bs4.BeautifulSoup(cont.content, "html5lib")
soup = bs4.BeautifulSoup(cont.content) # don't define the parser
# soup = bs4.BeautifulSoup(cont.content, "html.parser") # you could also try other parsers
Other suggestions
Your code will probably work without these, but you might want to consider these suggested improvements for error-handling:
Filter the script Tags
If the text ResultSet only has script tags that contain __bbox":, you avoid looping unnecessarily through the 100+ other scripts, and you won't have to check with if....find('__bbox":') anymore.
text = soup.find_all(lambda t: t.name == 'script' and '"__bbox"' in t.get_text())
for mystr in [s.get_text() for s in text]:
print("this is: ", mystr.find('__bbox":'))
txtstr += mystr
start = mystr.find('__bbox":') + len('__bbox":')
Initiate end
You should initiate the end variable [like end = 0] before the for end, char ... loop because you're using it after the loop as well.
print('end:', end)
data = json.loads(txtstr[start:end+1])
If txtstr[start:] is empty somehow, these lines will raise error/s since end would not be defined yet.
Use a JavaScript Parser
This will make the previous suggestions unnecessary, but as it is json.loads will raise an error if txtstr[start:end+1] is empty somehow, or if it contains any unpaired [and likely escaped] }or{. So, it might be more reliable to use a parser rather than just trying to walk through the string.
I have this function that uses slimit to find values from strings containing JavaScript code. (It's far from perfect, but it seems to for this script, at least.) GetIDs() could be re-written as below.
# import json, requests, bs4, slimit
# from slimit.visitors import nodevisitor
# def findObj_inJS... ## PASTE FROM https://pastebin.com/UVcLniSG
# class CmsIDs:
def GetIDs():
# cont=requests.get('https://www.facebook.com:443/help',headers=Static.headers)
cont = requests.get('https://www.facebook.com:443/help', headers={
'accept': ';'.join(
[ 'text/html,application/xhtml+xml,application/xml',
'q=0.9,image/avif,image/webp,image/apng,*/*',
'q=0.8,application/signed-exchange',
'v=b3', 'q=0.9' ])})
## in case of request errors ##
try: cont.raise_for_status()
except Exception as e:
print('failed to fetch page HTML -', type(e), e)
return
print('fetched', cont.url, 'with', cont.status_code, cont.reason)
soup = bs4.BeautifulSoup(cont.content)
scrCond = lambda t: t.name == 'script' and '"__bbox"' in t.get_text()
jScripts = [s.get_text() for s in soup.find_all(scrCond)]
print(f'Found {len(jScripts)} script tags containing {{"__bbox"}}')
data = [findObj_inJS(s,'"__bbox"') for s in jScripts]
print('--- search ---')
CmsIDs.search(data)
# def search(data)....
Return the Data
This isn't for error-handling, but if you return the data printed by CmsIDs.search you could save it for further use.
def search(data):
rList, dKeys = [], ['cms_object_id', 'cmsID', 'name']
if isinstance(data, dict):
dObj = {k: data[k] for k in dKeys if k in data}
rList += [dObj] if dObj else []
for k, v in dObj.items(): print(k, v)
if dObj: print('---')
for val in data.values(): rList += CmsIDs.search(val)
if isinstance(data, list):
for val in data: rList += CmsIDs.search(val)
return rList
The printed result will be the same as before, but if you change the last line of GetIDs to
return CmsIDs.search(data)
and then define a variable cmsList = CmsIDs.GetIDs() then cmsList will be a list of dctionaries, which you could then [for example] save to csv with pandas and view as a table on a spreadsheet.
# import pandas
pandas.DataFrame(cmsList).to_csv('CmsIDs_GetIDs.csv', index=False)
or print the markdown for the table [of the results I got] below
print(pandas.DataFrame(cmsList, dtype=str).fillna('').to_markdown())
[index]
cms_object_id
name
cmsID
0
Використання Facebook
1
570785306433644
Створення облікового запису
2
396528481579093
Your Profile
3
Додати й редагувати інформацію у своєму профілі
1017657581651994
4
Ваші основна світлина й обкладинка
1217373834962306
5
Поширення дописів у своєму профілі та керування ними
1640261589632787
6
Усунення проблем
191128814621591
7
1540345696275090
Додавання в друзі
8
Додавання друзів
246750422356731
9
Люди, яких ви можете знати
336320879782850
10
Control Who Can Friend and Follow You
273948399619967
11
Upload Your Contacts to Facebook
1041444532591371
12
Видалення з друзів чи блокування користувача
1000976436606344
13
312959615934334
Facebook Dating
14
753701661398957
Ваша головна сторінка
15
How Feed Works
1155510281178725
16
Control What You See in Feed
964154640320617
17
Like and React to Posts
1624177224568554
18
Пошук
821153694683665
19
Translate Feed
1195058957201487
20
Memories
1056848067697293
21
1071984682876123
Повідомлення
22
Надсилання повідомлень
487151698161671
23
Переглянути повідомлення й керувати ними
1117039378334299
24
Поскаржитися на повідомлення
968185709965912
25
Відеовиклики
287631408243374
26
Fix a Problem
1024559617598844
27
753046815962474
Reels
28
Watching Reels
475378724739085
29
Creating Reels
867690387846185
30
Managing Your Reels
590925116168623
31
862926927385914
Розповіді
32
Як створити розповідь і поширити її
126560554619115
33
View and Reply to Stories
349797465699432
34
Page Stories
425367811379971
35
1069521513115444
Світлини й відео
36
Світлини
1703757313215897
37
Відео
1738143323068602
38
Going Live
931327837299966
39
Albums
490693151131920
40
Додавання позначок
267689476916031
41
Усунення проблеми
507253956146325
42
1041553655923544
Відео у Watch
43
Перегляд шоу та відео
401287967326510
44
Fix a Problem
270093216665260
45
2402655169966967
Gaming
46
Gaming on Facebook
385894640264219
47
Платежі в іграх
248471068848455
48
282489752085908
Сторінки
49
Interact with Pages
1771297453117418
50
Створити сторінку й керувати нею
135275340210354
51
Імена й імена користувачів
1644118259243888
52
Керування налаштуваннями сторінки
1206330326045914
53
Customize a Page
1602483780062090
54
Publishing
1533298140275888
55
Messaging
994476827272050
56
Insights
794890670645072
57
Banning and Moderation
248844142141117
58
Усунути проблему
1020132651404616
59
1629740080681586
Групи
60
Join and Choose Your Settings
1210322209008185
61
Post, Participate and Privacy
530628541788770
62
Create, Engage and Manage Settings
408334464841405
63
Керування групою для адміністраторів
1686671141596230
64
Community Chats
3397387057158160
65
Pages in Groups
1769476376397128
66
Fix a Problem
1075368719167893
67
1076296042409786
Події
68
Create and Manage an Event
572885262883136
69
View and Respond to Events
1571121606521970
70
Facebook Classes
804063877226739
71
833144153745643
Fundraisers and Donations
72
Creating a Fundraiser
356680401435429
73
Пожертва в рамках збору коштів
1409509059114623
74
Особисті збори коштів
332739730519432
75
For Nonprofits
1640008462980459
76
Fix a Problem
2725517974129416
77
1434403039959381
Meta Pay
78
Платежі в іграх
248471068848455
79
Payments in Messages
863171203733904
80
Пожертва в рамках збору коштів
1409509059114623
81
Квитки на заходи
1769557403280350
82
Monetization and Payouts
1737820969853848
83
1713241952104830
Marketplace
84
Як працює Marketplace
1889067784738765
85
Buying on Marketplace
272975853291364
86
Продаж на Marketplace
153832041692242
87
Sell with Shipping on Marketplace
773379109714742
88
Using Checkout on Facebook
1411280809160810
89
Групи з купівлі й продажу
319768015124786
90
Get Help with Marketplace
1127970530677256
91
1642635852727373
Додатки
92
Manage Your Apps
942196655898243
93
Видимість і конфіденційність додатка
1727608884153160
94
866249956813928
Додатки Facebook для мобільних пристроїв
95
Додаток для Android
1639918076332350
96
iPhone and iPad Apps
1158027224227668
97
Facebook Lite App
795302980569545
98
273947702950567
Спеціальні можливості
99
Керування обліковим записом
100
1573156092981768
Вхід і пароль
101
Вхід в обліковий запис
1058033620955509
102
Змінення пароля
248976822124608
103
Виправлення проблеми із входом
283100488694834
104
Завантаження посвідчення особи
582999911881572
105
239070709801747
Налаштування облікового запису
106
Як змінити налаштування облікового запису
1221288724572426
107
Ваше ім’я користувача
1740158369563165
108
Спадкоємці
991335594313139
109
1090831264320592
Імена у Facebook
110
1036755649750898
Сповіщення
111
Push, Email and Text Notifications
530847210446227
112
Виберіть, про що отримувати сповіщення
269880466696699
113
Усунення проблем
1719980288275077
114
109378269482053
Налаштування реклами
115
Як працює реклама у Facebook
516147308587266
116
Контроль реклами, яку ви бачите
1075880512458213
117
Ваша інформація та реклама у Facebook
610457675797481
118
1701730696756992
Доступ до вашої інформації та її завантаження
119
250563911970368
Деактивація або видалення облікового запису
120
Конфіденційність і безпека
121
238318146535333
Ваша конфіденційність
122
Керуйте тим, хто може переглядати контент, який ви поширюєте у Facebook
1297502253597210
123
Керування своїми дописами
504765303045427
124
Control Who Can Find You
1718866941707011
125
592679377575472
Безпека
126
Джерела щодо боротьби з жорстоким поводженням
726709730764837
127
Ресурси з допомоги для протидії самогубству та самоушкодженню
1553737468262661
128
Crisis Response
141874516227713
129
Ресурси з правил безпеки для допомоги батькам
1079477105456277
130
Інформація для правоохоронних органів
764592980307837
131
235353253505947
Захист облікового запису
132
Функції безпеки та поради з її забезпечення
285695718429403
133
Сповіщення про вхід і двоетапна перевірка
909243165853369
134
Уникайте спаму та шахрайства
1584206335211143
135
236079651241697
Безпека під час здійснення покупок
136
Розпізнавання шахрайства
1086141928978559
137
Уникнення шахрайства
2374002556073992
138
Купівля на Marketplace
721562085854101
139
Поради щодо безпечної купівлі
123884166448529
140
Купуйте впевнено
1599248863596914
141
Політики та скарги
142
1753719584844061
Скарга на порушення
143
Як поскаржитися на щось?
1380418588640631
144
Don't Have an Account?
1723400564614772
145
1126628984024935
Як повідомити про проблему у Facebook
146
186614050293763
Being Your Authentic Self on Facebook
147
1561472897490627
Повідомлення про порушення конфіденційності
148
1216349518398524
Зламані та фальшиві облікові записи
149
275013292838654
Керування обліковим записом померлої людини
150
About Memorialized Accounts
1017717331640041
151
Request to Memorialize or Remove an Account
1111566045566400
152
399224883474207
Інтелектуальна власність
153
Авторське право
1020633957973118
154
Торговельна марка
507663689427413
155
1735443093393986
Про наші політики

dataframe put must be a unicode string, not 0, how give the string not the dataframe

i try to manipulate some dataframe and i did a function to calculate the distance between 2 cities.
def find_distance(A,B):
key = '0377f0e6b42a47fe9d30a4e9a2b3bb63' # get api key from: https://opencagedata.com
geocoder = OpenCageGeocode(key)
result_A = geocoder.geocode(A)
lat_A = result_A[0]['geometry']['lat']
lng_A = result_A[0]['geometry']['lng']
result_B = geocoder.geocode(B)
lat_B = result_B[0]['geometry']['lat']
lng_B = result_B[0]['geometry']['lng']
return int(geodesic((lat_A,lng_A), (lat_B,lng_B)).kilometers)
this is my dataframe
2 32 Mulhouse 1874.0 2 797 16.8 16,3 € 10.012786
13 13 Saint-Étienne 1994.0 3 005 14.3 13,5 € 8.009882
39 39 Roubaix 2845.0 2 591 17.4 15,0 € 6.830968
27 27 Perpignan 2507.0 3 119 15.1 13,3 € 6.727255
40 40 Tourcoing 3089.0 2 901 17.5 15,3 € 6.327547
25 25 Limoges 2630.0 2 807 14.2 12,5 € 6.030424
20 20 Le Mans 2778.0 3 202 14.4 12,3 € 5.789559
there is my code:
def clean_text(row):
# return the list of decoded cell in the Series instead
return [r.decode('unicode_escape').encode('ascii', 'ignore') for r in row]
def main():
inFile = "prix_m2_france.xlsx" #On ouvre l'excel
inSheetName = "Sheet1" #le nom de l excel
cols = ['Ville', 'Prix_moyen', 'Loyer_moyen'] #Les colomnes
df =(pd.read_excel(inFile, sheet_name = inSheetName))
df[cols] = df[cols].replace({'€': '', ",": ".", " ": "", "\u202f":""}, regex=True)
# df['Prix_moyen'] = df.apply(clean_text)
# df['Loyer_moyen'] = df.apply(clean_text)
df['Prix_moyen'] = df['Prix_moyen'].astype(float)
df['Loyer_moyen'] = df['Loyer_moyen'].astype(float)
# df["Prix_moyen"] += 1
df["revenu"] = (df['Loyer_moyen'] * 12) / (df["Prix_moyen"] * 1.0744) * 100
# df['Ville'].replace({'Le-Havre': 'Le Havre', 'Le-Mans': 'Le Mans'})
df["Ville"] = df['Ville'].replace(['Le-Havre', 'Le-Mans'], ['Le Havre', 'Le Mans'])
df["distance"] = find_distance("Paris", df["Ville"])
df2 = df.sort_values(by = 'revenu', ascending = False)
print(df2.head(90))
main()
df["distance"] = find_distance("Paris", df["Ville"]) fails and give me this error:
opencage.geocoder.InvalidInputError: Input must be a unicode string, not 0 Paris
1 Marseille
2 Lyon
3 T
I imagine it as a loop where i will put the distance between paris and the city but i guess it take all the dataframe on my first value.
Thanks for your help
(Edit, i just pasted a part of my dataframe)
You can try something like :
df["distance"] = [find_distance("Paris", city) for city in df["Ville"]]

How to create EddyStone Beacon using BlueZ and Python?

I'm working on BLE(BlueTooth Low Energy) on an Embedded Linux board. We use BlueZ and Python. I need to create EddyStone Beacon. I found there is a way to create iBeacon: https://scribles.net/creating-ibeacon-using-bluez-example-code-on-raspberry-pi/. I tried it. It worked.
But we need to create EddyStone Beacon. So I use the Beacon data format from here(https://ukbaz.github.io/howto/beacon_scan_cmd_line.html) to create the manufacturer data.
But my code doesn't work. What is wrong with my code? Here is my code:
def __init__(self, bus, index):
eddystone_id = 0xAAFE
beacon_type = [0x14, 0x16] # Length = 0x14, EddyStone type = 0x16
uuid = [0xAA, 0xFE] # EddyStone UUID = 0xAAFE
frame_type = [0x10] # Frame Type = 0x10
power = [0x00] # Power = 0x00
prefix = [0x02] # URL scheme = 0x02 (http://)
url = [0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x77, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x07]
Advertisement.__init__(self, bus, index, 'peripheral')
self.add_manufacturer_data(eddystone_id, beacon_type + uuid + frame_type + power + prefix + url)
However, if I use this command, the EddyStone Beacon is created. I can see it shows EddyStone Beacon in nRF mobile app:
sudo hcitool -i hci0 cmd 0x08 0x0008 1c 02 01 06 03 03 aa fe 14 16 aa fe 10 00 02 73 61 6d 70 6c 65 77 65 62 73 69 74 65 07 00 00 00
As you can see, the data I put in the add_manufacturer_data() function is the same as the data in the command. But why the Python code doesn't work?
iBeacon uses manufacturer_data while Eddystone beacons use service_data so I would expect your code to look more like this:
def __init__(self, bus, index):
Advertisement.__init__(self, bus, index, 'broadcast')
self.add_service_uuid('FEAA')
frame_type = [0x10] # Eddystone frame Type = 0x10
power = [0x00] # Beacon broadcast power = 0x00
prefix = [0x02] # URL scheme = 0x02 (http://)
url = [0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x77, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x07]
eddystone_data = frame_type + power + prefix + url
self.add_service_data('FEAA', eddystone_data)
As a side note, hcitool is one of the tools that has been deprecated by the BlueZ developers. The currently supported way to create the Eddystone beacon from the command line would be with bluetoothctl. The sequence of commands would be:
bluetoothctl
menu advertise
uuids 0xFEAA
service 0xFEAA 0x10 0x00 0x02 0x73 0x61 0x6D 0x70 0x6C 0x65 0x77 0x65 0x62 0x73 0x69 0x74 0x65 0x07
back
advertise broadcast
discoverable on
I changed the advertisement type from peripheral to broadcast because typically people don't want beacons to be connectable, but it depends on your application.

In python with pywin32, win32job, the CreateJobObject function, how do I pass NULL for the name parameter?

I'm trying to use the win32job API that is part of the PyWin32 package. I want to do this:
win32job.CreateJobObject(None, NULL)
I want to pass NULL as the second parameter as documented here:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms682409(v=vs.85).aspx
If lpName is NULL, the job is created without a name.
How do I pass in NULL?
Here's what I hoped would work, but doesn't:
win32job.CreateJobObject(None, None)
Error:
TypeError: None is not a valid string in this context
(Side question... if anyone knows how to view JobObjects associated with a process in Windows, that would be helpful.)
You can use win32job.CreateJobObject(None, ""). Although it isn't specified on [MS.Docs]: CreateJobObjectA function, the empty string acts just like NULL.
According to the link above:
If the function succeeds, the return value is a handle to the job object. The handle has the JOB_OBJECT_ALL_ACCESS access right. If the object existed before the function call, the function returns a handle to the existing job object and GetLastError returns ERROR_ALREADY_EXISTS.
I wrote a small C program for demonstrating purposes:
#include <Windows.h>
#include <stdio.h>
#define EMPTY_TEXT ""
#define DUMMY0_TEXT "dummy0"
#define DUMMY1_TEXT "dummy1"
#define DIM 12
int main() {
char* names[DIM] = { NULL, NULL, EMPTY_TEXT, EMPTY_TEXT, DUMMY0_TEXT,
DUMMY0_TEXT, EMPTY_TEXT, DUMMY0_TEXT, DUMMY1_TEXT,
NULL, DUMMY0_TEXT, DUMMY1_TEXT };
HANDLE jobs[DIM] = { NULL };
for (int i = 0; i < DIM; i++) {
jobs[i] = CreateJobObjectA(NULL, names[i]);
printf("%02d [%6s] CreateJobObject: %08X - GetLastError: %d\n", i, names[i], (long)jobs[i], GetLastError());
}
for (int i = 0; i < DIM; i++)
CloseHandle(jobs[i]);
return 0;
}
Output (built and ran with VStudio 2015 Community Edition):
00 [(null)] CreateJobObject: 000000D8 - GetLastError: 0
01 [(null)] CreateJobObject: 000000E0 - GetLastError: 0
02 [ ] CreateJobObject: 00000088 - GetLastError: 0
03 [ ] CreateJobObject: 000000F0 - GetLastError: 0
04 [dummy0] CreateJobObject: 000000F4 - GetLastError: 0
05 [dummy0] CreateJobObject: 000000F8 - GetLastError: 183
06 [ ] CreateJobObject: 000000E8 - GetLastError: 0
07 [dummy0] CreateJobObject: 000000FC - GetLastError: 183
08 [dummy1] CreateJobObject: 00000100 - GetLastError: 0
09 [(null)] CreateJobObject: 000000DC - GetLastError: 0
10 [dummy0] CreateJobObject: 000000E4 - GetLastError: 183
11 [dummy1] CreateJobObject: 00000104 - GetLastError: 183
You can see that for "dummy0" and "dummy", every time (excepting the 1st) when creating a new object, the function does return a new HANDLE, but fails (GetLastError returns 183 (which is ERROR_ALREADY_EXISTS)). This doesn't happen for NULL and the empty string names (from here I understand that a new object is created with every call instead of incrementing an existing object's reference).
Python "translation" (code.py):
#!/usr/bin/env python3
import win32job
import win32api
DUMMY0 = "dummy00"
DUMMY1 = "dummy11"
JOB_NAMES = ["", "", DUMMY0, DUMMY0, "", DUMMY1, DUMMY0, "", DUMMY1]
if __name__ == "__main__":
handles = list()
for i, name in enumerate(JOB_NAMES):
h = win32job.CreateJobObject(None, name)
print("{} [{:10}] {} - GetLastError: {}".format(i, name, h, win32api.GetLastError()))
handles.append(h)
for h in handles:
win32api.CloseHandle(h)
Output (same result as in C's case - which is natural since Python functions only wrap the lower level C ones):
(py35x64_test) e:\Work\Dev\StackOverflow\q046800142>"c:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" code.py
0 [ ] <PyHANDLE:300> - GetLastError: 0
1 [ ] <PyHANDLE:308> - GetLastError: 0
2 [dummy00 ] <PyHANDLE:580> - GetLastError: 0
3 [dummy00 ] <PyHANDLE:584> - GetLastError: 183
4 [ ] <PyHANDLE:588> - GetLastError: 0
5 [dummy11 ] <PyHANDLE:592> - GetLastError: 0
6 [dummy00 ] <PyHANDLE:596> - GetLastError: 183
7 [ ] <PyHANDLE:600> - GetLastError: 0
8 [dummy11 ] <PyHANDLE:604> - GetLastError: 183
Regarding the "side" question: unfortunately, I'm not familiar with that topic.

hadoop mapreduce with python error in implement of two table join

I'm new to hadoop. I use python to implement a join of two table.
A table with student info as stu id and name and another table with grade info as stu id, class id and grade.(The data is in the end of this question)
with cat ./data* | python mapper.py |sort| python reducer.py
I get the right answer, however in the hadoop process, I get the following error:
INFO mapreduce.Job: Task Id : attempt_1456069308240_0019_m_000001_2, Status : FAILED
Error: java.lang.RuntimeException: PipeMapRed.waitOutputThreads(): subprocess failed with code 2
the code is below:
mapper code:
import os
import sys
def mapper():
for line in sys.stdin:
if len(line.strip())== 0:
continue
field = line[:-1].split('\t')
if len(field) ==2:
print '%s\t%s\t%s' % (field[0],'0',field[1])
elif len(field) ==3:
print '%s\t%s\t%s\t%s' % (field[0],'1',field[1],field[2])
if __name__=='__main__':
mapper()
reducer code:
def reducer():
lastsno=""
for line in sys.stdin:
if len(line.strip())== 0:
continue
field = line[:-1].split('\t')
sno = field[0]
if sno != lastsno:
name = ""
if field[1] == "0":
name = field[2]
elif sno == lastsno:
if field[1] == "1":
courseno =field[2]
grade = field[3]
if name:
print '%s\t%s\t%s\t%s' % (lastsno,name,courseno,grade)
lastsno = sno
if __name__=='__main__':
reducer()
the data is just below
datainfo:
2014211011 taiyuan
2014211012 tiantian
2014211013 kk
2014211014 tank
2014211015 lc
2014211016 wjs
2014211017 gyc
2014211018 hd
2014211019 cx
data_grade:
2014211012 011 80
2014211012 012 95
2014211013 011 40
2014211014 013 38
2014211011 011 35
2014211013 022 40
2014211015 011 80
with above cat python script, I can get right answer below:
2014211011 taiyuan 011 35
2014211012 tiantian 011 80
2014211012 tiantian 012 95
2014211013 kk 011 40
2014211013 kk 022 40
2014211014 tank 013 38
2014211015 lc 011 80
But error in hadoop, please help me, Thanks.

Categories