Skip to content

Commit 19dd805

Browse files
authored
Merge pull request #1 from koolsb/addip
Add IP support
2 parents 546a511 + c763655 commit 19dd805

File tree

5 files changed

+136
-55
lines changed

5 files changed

+136
-55
lines changed

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,12 @@ This is for use with [Home-Assistant](http://home-assistant.io)
1010
```python
1111
from pyblackbird import get_blackbird
1212

13+
# Connect via serial port
1314
blackbird = get_blackbird('/dev/ttyUSB0')
1415

16+
# Connect via IP
17+
blackbird = get_blackbird('192.168.1.50', use_serial=False)
18+
1519
# Print system lock status
1620
print('System Lock is {}'.format('On' if blackbird.lock_status() else 'Off'))
1721

pyblackbird/__init__.py

+69-33
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import logging
44
import re
55
import serial
6+
import socket
67
from functools import wraps
78
from serial_asyncio import create_serial_connection
89
from threading import RLock
@@ -13,7 +14,8 @@
1314
EOL = b'\r'
1415
LEN_EOL = len(EOL)
1516
TIMEOUT = 2 # Number of seconds before serial operation timeout
16-
SYSTEM_POWER = None
17+
PORT = 4001
18+
SOCKET_RECV = 2048
1719

1820
class ZoneStatus(object):
1921
def __init__(self,
@@ -53,6 +55,7 @@ def from_string(cls, string: str):
5355
else:
5456
return False
5557

58+
5659
class Blackbird(object):
5760
"""
5861
Monoprice blackbird amplifier interface
@@ -134,13 +137,14 @@ def _format_lock_status() -> bytes:
134137
return '%9961.\r'.encode()
135138

136139

137-
def get_blackbird(port_url):
140+
def get_blackbird(url, use_serial=True):
138141
"""
139142
Return synchronous version of Blackbird interface
140143
:param port_url: serial port, i.e. '/dev/ttyUSB0'
141144
:return: synchronous implementation of Blackbird interface
142145
"""
143146
lock = RLock()
147+
print(serial)
144148

145149
def synchronized(func):
146150
@wraps(func)
@@ -150,44 +154,76 @@ def wrapper(*args, **kwargs):
150154
return wrapper
151155

152156
class BlackbirdSync(Blackbird):
153-
def __init__(self, port_url):
154-
self._port = serial.serial_for_url(port_url, do_not_open=True)
155-
self._port.baudrate = 9600
156-
self._port.stopbits = serial.STOPBITS_ONE
157-
self._port.bytesize = serial.EIGHTBITS
158-
self._port.parity = serial.PARITY_NONE
159-
self._port.timeout = TIMEOUT
160-
self._port.write_timeout = TIMEOUT
161-
self._port.open()
157+
def __init__(self, url):
158+
"""
159+
Initialize the client.
160+
"""
161+
if use_serial:
162+
self._port = serial.serial_for_url(url, do_not_open=True)
163+
self._port.baudrate = 9600
164+
self._port.stopbits = serial.STOPBITS_ONE
165+
self._port.bytesize = serial.EIGHTBITS
166+
self._port.parity = serial.PARITY_NONE
167+
self._port.timeout = TIMEOUT
168+
self._port.write_timeout = TIMEOUT
169+
self._port.open()
170+
171+
else:
172+
self.host = url
173+
self.port = PORT
174+
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
175+
self.socket.settimeout(TIMEOUT)
176+
self.socket.connect((self.host, self.port))
177+
178+
# Clear login message
179+
self.socket.recv(SOCKET_RECV)
162180

163181
def _process_request(self, request: bytes, skip=0):
164182
"""
183+
Send data to socket
165184
:param request: request that is sent to the blackbird
166185
:param skip: number of bytes to skip for end of transmission decoding
167186
:return: ascii string returned by blackbird
168187
"""
169188
_LOGGER.debug('Sending "%s"', request)
170-
# clear
171-
self._port.reset_output_buffer()
172-
self._port.reset_input_buffer()
173-
# send
174-
self._port.write(request)
175-
self._port.flush()
176-
# receive
177-
result = bytearray()
178-
while True:
179-
c = self._port.read(1)
180-
if c is None:
181-
break
182-
if not c:
183-
raise serial.SerialTimeoutException(
184-
'Connection timed out! Last received bytes {}'.format([hex(a) for a in result]))
185-
result += c
186-
if len(result) > skip and result [-LEN_EOL:] == EOL:
187-
break
188-
ret = bytes(result)
189-
_LOGGER.debug('Received "%s"', ret)
190-
return ret.decode('ascii')
189+
190+
if use_serial:
191+
# clear
192+
self._port.reset_output_buffer()
193+
self._port.reset_input_buffer()
194+
# send
195+
self._port.write(request)
196+
self._port.flush()
197+
# receive
198+
result = bytearray()
199+
while True:
200+
c = self._port.read(1)
201+
if c is None:
202+
break
203+
if not c:
204+
raise serial.SerialTimeoutException(
205+
'Connection timed out! Last received bytes {}'.format([hex(a) for a in result]))
206+
result += c
207+
if len(result) > skip and result [-LEN_EOL:] == EOL:
208+
break
209+
ret = bytes(result)
210+
_LOGGER.debug('Received "%s"', ret)
211+
return ret.decode('ascii')
212+
213+
else:
214+
self.socket.send(request)
215+
216+
response = ''
217+
218+
while True:
219+
220+
data = self.socket.recv(SOCKET_RECV)
221+
response += data.decode('ascii')
222+
223+
if EOL in data and len(response) > skip:
224+
break
225+
226+
return response
191227

192228
@synchronized
193229
def zone_status(self, zone: int):
@@ -224,7 +260,7 @@ def lock_status(self):
224260
# Report system locking status
225261
return LockStatus.from_string(self._process_request(_format_lock_status()))
226262

227-
return BlackbirdSync(port_url)
263+
return BlackbirdSync(url)
228264

229265

230266
@asyncio.coroutine

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import os
44
import sys
55

6-
VERSION = '0.4'
6+
VERSION = '0.5'
77

88
try:
99
from setuptools import setup

tests/__init__.py

+60-19
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,66 @@
11
import threading
22
import os
33
import pty
4+
import socket
45

56

67
def create_dummy_port(responses):
7-
def listener(port):
8-
# continuously listen to commands on the master device
9-
while 1:
10-
res = b''
11-
while not res.endswith(b"\r"):
12-
# keep reading one byte at a time until we have a full line
13-
res += os.read(port, 1)
14-
print("command: %s" % res)
15-
16-
# write back the response
17-
if res in responses:
18-
resp = responses[res]
19-
del responses[res]
20-
os.write(port, resp)
21-
22-
master, slave = pty.openpty()
23-
thread = threading.Thread(target=listener, args=[master], daemon=True)
24-
thread.start()
25-
return os.ttyname(slave)
8+
def listener(port):
9+
# continuously listen to commands on the master device
10+
while 1:
11+
res = b''
12+
while not res.endswith(b"\r"):
13+
# keep reading one byte at a time until we have a full line
14+
res += os.read(port, 1)
15+
print("command: %s" % res)
16+
17+
# write back the response
18+
if res in responses:
19+
resp = responses[res]
20+
del responses[res]
21+
os.write(port, resp)
22+
23+
master, slave = pty.openpty()
24+
thread = threading.Thread(target=listener, args=[master], daemon=True)
25+
thread.start()
26+
return os.ttyname(slave)
27+
28+
def create_dummy_socket(responses):
29+
HOST = '127.0.0.1'
30+
PORT = 4001
31+
32+
33+
34+
def listener():
35+
36+
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
37+
conn.bind((HOST, PORT))
38+
conn.listen(10)
39+
40+
while 1:
41+
conn, addr = s.accept()
42+
43+
conn.send('Please Input Your Command :\r')
44+
45+
while True:
46+
# Receive data
47+
res = conn.recv(1024)
48+
print("command: %s" % res)
49+
50+
# write back the response
51+
if res in responses:
52+
resp = responses[res]
53+
del responses[res]
54+
conn.sendall(resp)
55+
56+
if not res:
57+
break
58+
59+
#while 1:
60+
61+
# start_new_thread(listener ,(conn,))
62+
63+
thread = threading.Thread(target=listener, daemon=True)
64+
thread.start()
65+
66+
return HOST

tests/test_blackbird.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import serial
44

55
from pyblackbird import (get_blackbird, get_async_blackbird, ZoneStatus)
6-
from tests import create_dummy_port
6+
from tests import (create_dummy_port, create_dummy_socket)
77
import asyncio
88

99

@@ -108,4 +108,4 @@ def test_timeout(self):
108108
self.blackbird.set_zone_source(6, 6)
109109

110110
if __name__ == '__main__':
111-
unittest.main()
111+
unittest.main()

0 commit comments

Comments
 (0)