-
Notifications
You must be signed in to change notification settings - Fork 17
/
device_pyusb.py
181 lines (137 loc) · 6.34 KB
/
device_pyusb.py
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# pywws - Python software for USB Wireless Weather Stations
# http://github.com/jim-easterbrook/pywws
# Copyright (C) 2008-13 Jim Easterbrook jim@jim-easterbrook.me.uk
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""Low level USB interface to weather station, using PyUSB.
Introduction
============
This module handles low level communication with the weather station
via the `PyUSB <http://sourceforge.net/apps/trac/pyusb/>`_ library. An
alternative module, :doc:`pywws.device_cython_hidapi`, uses the
`cython-hidapi <https://github.com/gbishop/cython-hidapi>`_ library.
The choice of which module to use depends on which libraries are
available for you computer.
Users of recent versions of Mac OS have no choice. The operating
system makes it very difficult to access HID devices (such as the
weather station) directly, so the ``hidapi`` library has to be used.
``cython-hidapi`` is a Python interface to that library.
Users of OpenWRT and similar embedded Linux platforms will probably
not be able to install ``cython-hidapi``, so are constrained to use
``libusb`` and its ``PyUSB`` Python interface.
Installation
============
Some of this software may already be installed on your machine, so do
check before downloading sources and compiling them yourself.
#. Install libusb and PyUSB.
These should be available as packages for your operating system,
but their names may vary. For example, on Ubuntu Linux::
sudo apt-get install libusb-0.1 python-usb
On some embedded linux systems::
ipkg install libusb py25-usb
Testing
=======
Run ``TestWeatherStation.py`` with increased verbosity so it reports
which USB device access module is being used::
python TestWeatherStation.py -vv
18:28:09:pywws.WeatherStation.CUSBDrive:using pywws.device_pyusb
0000 55 aa ff ff ff ff ff ff ff ff ff ff ff ff ff ff 05 20 01 41 11 00 00 00 81 00 00 0f 05 00 e0 51
0020 03 27 ce 27 00 00 00 00 00 00 00 12 02 14 18 27 41 23 c8 00 00 00 46 2d 2c 01 64 80 c8 00 00 00
0040 64 00 64 80 a0 28 80 25 a0 28 80 25 03 36 00 05 6b 00 00 0a 00 f4 01 12 00 00 00 00 00 00 00 00
0060 00 00 49 0a 63 12 05 01 7f 00 36 01 60 80 36 01 60 80 bc 00 7b 80 95 28 12 26 6c 28 25 26 c8 01
0080 1d 02 d8 00 de 00 ff 00 ff 00 ff 00 00 11 10 06 01 29 12 02 01 19 32 11 09 09 05 18 12 01 22 13
00a0 14 11 11 04 15 04 11 12 17 05 12 11 09 02 15 26 12 02 11 07 05 11 09 02 15 26 12 02 11 07 05 11
00c0 09 10 09 12 12 02 02 12 38 12 02 07 19 00 11 12 16 03 27 12 02 03 11 00 11 12 16 03 27 11 12 26
00e0 21 32 11 12 26 21 32 12 02 06 19 57 12 02 06 19 57 12 02 06 19 57 12 02 06 19 57 12 02 06 19 57
API
===
"""
__docformat__ = "restructuredtext en"
import platform
import usb
class USBDevice(object):
def __init__(self, idVendor, idProduct):
"""Low level USB device access via PyUSB library.
:param idVendor: the USB ``vendor ID` number, for example 0x1941.
:type idVendor: int
:param idProduct: the USB ``product ID` number, for example 0x8021.
:type idProduct: int
"""
dev = self._find_device(idVendor, idProduct)
if not dev:
raise IOError("Weather station device not found")
self.devh = dev.open()
if not self.devh:
raise IOError("Open device failed")
## if platform.system() is 'Windows':
## self.devh.setConfiguration(1)
try:
self.devh.claimInterface(0)
except usb.USBError:
# claim interface failed, try detaching kernel driver first
if not hasattr(self.devh, 'detachKernelDriver'):
raise RuntimeError(
"Please upgrade pyusb (or python-usb) to 0.4 or higher")
try:
self.devh.detachKernelDriver(0)
self.devh.claimInterface(0)
except usb.USBError:
raise IOError("Claim interface failed")
# device may have data left over from an incomplete read
for i in range(4):
try:
self.devh.interruptRead(0x81, 8, 1200)
except usb.USBError:
break
def __del__(self):
if self.devh:
try:
self.devh.releaseInterface()
except usb.USBError:
# interface was not claimed. No problem
pass
def _find_device(self, idVendor, idProduct):
"""Find a USB device by product and vendor id."""
for bus in usb.busses():
for device in bus.devices:
if (device.idVendor == idVendor and
device.idProduct == idProduct):
return device
return None
def read_data(self, size):
"""Receive data from the device.
If the read fails for any reason, an :obj:`IOError` exception
is raised.
:param size: the number of bytes to read.
:type size: int
:return: the data received.
:rtype: list(int)
"""
result = self.devh.interruptRead(0x81, size, 1200)
if result is None or len(result) < size:
raise IOError('pywws.device_libusb.USBDevice.read_data failed')
return list(result)
def write_data(self, buf):
"""Send data to the device.
If the write fails for any reason, an :obj:`IOError` exception
is raised.
:param buf: the data to send.
:type buf: list(int)
:return: success status.
:rtype: bool
"""
result = self.devh.controlMsg(
usb.ENDPOINT_OUT + usb.TYPE_CLASS + usb.RECIP_INTERFACE,
usb.REQ_SET_CONFIGURATION, buf, value=0x200, timeout=50)
if result != len(buf):
raise IOError('pywws.device_libusb.USBDevice.write_data failed')
return True