Skip to content

Commit

Permalink
Refactor connection:
Browse files Browse the repository at this point in the history
- device.auto_connect() => mDNS
- device.connect("ip_address") => Manual connection
  • Loading branch information
CharlesBlonde committed Aug 5, 2017
1 parent 359e486 commit 58c1fa9
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 51 deletions.
4 changes: 2 additions & 2 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ Automatic connection (mDNS)
devices = dyson_account.devices()
# Connect using discovery to the first device
connected = devices[0].connect()
connected = devices[0].auto_connect()
# connected == device available, state values are available, sensor values are available
Expand All @@ -155,7 +155,7 @@ Manual connection
devices = dyson_account.devices()
# Connect using discovery to the first device
connected = devices[0].connect(device_ip="192.168.1.2")
connected = devices[0].connect("192.168.1.2")
# connected == device available, state values are available, sensor values are available
Expand Down
10 changes: 5 additions & 5 deletions libpurecoollink/dyson_360_eye.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,25 @@

import paho.mqtt.client as mqtt

from .dyson_device import DysonDevice, NetworkDevice
from .dyson_device import DysonDevice, NetworkDevice, DEFAULT_PORT
from .utils import printable_fields
from .const import PowerMode, Dyson360EyeMode, Dyson360EyeCommand

_LOGGER = logging.getLogger(__name__)

DEFAULT_PORT = 1883


class Dyson360Eye(DysonDevice):
"""Dyson 360 Eye device."""

def connect(self, device_ip):
def connect(self, device_ip, device_port=DEFAULT_PORT):
"""Try to connect to device.
:param device_ip: Device IP address
:param device_port: Device Port (default: 1883)
:return: True if connected, else False
"""
self._network_device = NetworkDevice(self._name, device_ip,
DEFAULT_PORT)
device_port)

self._mqtt = mqtt.Client(userdata=self, protocol=3)
self._mqtt.username_pw_set(self._serial, self._credentials)
Expand Down
12 changes: 12 additions & 0 deletions libpurecoollink/dyson_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
5: "Connection refused - not authorised"
}

DEFAULT_PORT = 1883


class NetworkDevice:
"""Network device."""
Expand Down Expand Up @@ -104,6 +106,16 @@ def connection_callback(self, connected):
"""Set function called when device is connected."""
self._connection_queue.put_nowait(connected)

@abc.abstractmethod
def connect(self, device_ip, device_port=DEFAULT_PORT):
"""Connect to the device using ip address.
:param device_ip: Device IP address
:param device_port: Device Port (default: 1883)
:return: True if connected, else False
"""
return

@property
@abc.abstractmethod
def status_topic(self):
Expand Down
71 changes: 37 additions & 34 deletions libpurecoollink/dyson_pure_cool_link.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,14 @@

import paho.mqtt.client as mqtt

from .dyson_device import DysonDevice, NetworkDevice
from .dyson_device import DysonDevice, NetworkDevice, DEFAULT_PORT
from .utils import printable_fields, support_heating
from .dyson_pure_state import DysonPureHotCoolState, DysonPureCoolState, \
DysonEnvironmentalSensorState
from .zeroconf import ServiceBrowser, Zeroconf

_LOGGER = logging.getLogger(__name__)

DEFAULT_PORT = 1883


class DysonPureCoolLink(DysonDevice):
"""Dyson device (fan)."""
Expand Down Expand Up @@ -103,41 +101,47 @@ def on_message(client, userdata, msg):
else:
_LOGGER.warning("Unknown message: %s", payload)

def connect(self, on_message=None, device_ip=None, timeout=5, retry=15):
"""Try to connect to device.
If device_ip is provided, mDNS discovery step will be skipped.
def auto_connect(self, timeout=5, retry=15):
"""Try to connect to device using mDNS.
:param on_message: On Message callback function
:param device_ip: Device IP address
:param timeout: Timeout
:param retry: Max retry
:return: True if connected, else False
"""
if device_ip is None:
for i in range(retry):
zeroconf = Zeroconf()
listener = self.DysonDeviceListener(self._serial,
self._add_network_device)
ServiceBrowser(zeroconf, "_dyson_mqtt._tcp.local.", listener)
try:
self._network_device = self._search_device_queue.get(
timeout=timeout)
except Empty:
# Unable to find device
_LOGGER.warning("Unable to find device %s, try %s",
self._serial, i)
zeroconf.close()
else:
break
if self._network_device is None:
_LOGGER.error("Unable to connect to device %s", self._serial)
return False
else:
self._network_device = NetworkDevice(self._name, device_ip,
DEFAULT_PORT)
for i in range(retry):
zeroconf = Zeroconf()
listener = self.DysonDeviceListener(self._serial,
self._add_network_device)
ServiceBrowser(zeroconf, "_dyson_mqtt._tcp.local.", listener)
try:
self._network_device = self._search_device_queue.get(
timeout=timeout)
except Empty:
# Unable to find device
_LOGGER.warning("Unable to find device %s, try %s",
self._serial, i)
zeroconf.close()
else:
break
if self._network_device is None:
_LOGGER.error("Unable to connect to device %s", self._serial)
return False
return self._mqtt_connect()

def connect(self, device_ip, device_port=DEFAULT_PORT):
"""Connect to the device using ip address.
if on_message:
self._callback_message.append(on_message)
:param device_ip: Device IP address
:param device_port: Device Port (default: 1883)
:return: True if connected, else False
"""
self._network_device = NetworkDevice(self._name, device_ip,
device_port)

return self._mqtt_connect()

def _mqtt_connect(self):
"""Connect to the MQTT broker."""
self._mqtt = mqtt.Client(userdata=self)
self._mqtt.on_message = self.on_message
self._mqtt.on_connect = self.on_connect
Expand All @@ -159,7 +163,6 @@ def connect(self, on_message=None, device_ip=None, timeout=5, retry=15):
self._device_available = True
else:
self._mqtt.loop_stop()

return self._connected

def sensor_data_available(self):
Expand Down
20 changes: 10 additions & 10 deletions tests/test_libpurecoollink.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ def test_connect_device(self, mocked_connect, mocked_loop):
device.sensor_data_available()
device.connection_callback(True)
device._add_network_device(network_device)
connected = device.connect(None)
connected = device.auto_connect()
self.assertTrue(connected)
self.assertIsNone(device.state)
self.assertEqual(device.network_device, network_device)
Expand All @@ -158,7 +158,7 @@ def test_connect_device_with_config(self, mocked_connect, mocked_loop):
device.connection_callback(True)
device.state_data_available()
device.sensor_data_available()
connected = device.connect(Mock(), "192.168.0.2")
connected = device.connect("192.168.0.2")
self.assertTrue(connected)
self.assertIsNone(device.state)
self.assertEqual(device.network_device.name, "device-1")
Expand Down Expand Up @@ -189,7 +189,7 @@ def test_connect_device_with_config_failed(self,
"ProductType": "475"
})
device.connection_callback(False)
connected = device.connect(Mock(), "192.168.0.2")
connected = device.connect("192.168.0.2")
self.assertFalse(connected)
self.assertIsNone(device.state)
self.assertEqual(device.network_device.name, "device-1")
Expand All @@ -214,7 +214,7 @@ def test_connect_device_fail(self, mocked_close_zeroconf):
"NewVersionAvailable": False,
"ProductType": "475"
})
connected = device.connect(None, retry=1, timeout=1)
connected = device.auto_connect(retry=1, timeout=1)
self.assertFalse(connected)
self.assertEqual(mocked_close_zeroconf.call_count, 1)

Expand Down Expand Up @@ -465,7 +465,7 @@ def test_set_configuration(self, mocked_connect, mocked_publish):
device.connection_callback(True)
device.state_data_available()
device.sensor_data_available()
connected = device.connect(None)
connected = device.auto_connect()
self.assertTrue(connected)
self.assertEqual(mocked_connect.call_count, 1)
device.set_configuration(fan_mode=FanMode.FAN,
Expand Down Expand Up @@ -507,7 +507,7 @@ def test_set_configuration_hot(self, mocked_connect, mocked_publish):
device.connection_callback(True)
device.state_data_available()
device.sensor_data_available()
connected = device.connect(None)
connected = device.auto_connect()
self.assertTrue(connected)
self.assertEqual(mocked_connect.call_count, 1)
device.set_configuration(fan_mode=FanMode.FAN,
Expand Down Expand Up @@ -553,7 +553,7 @@ def test_set_configuration_rst_filter(self, mocked_connect,
device.connection_callback(True)
device.state_data_available()
device.sensor_data_available()
connected = device.connect(None)
connected = device.auto_connect()
self.assertTrue(connected)
self.assertEqual(mocked_connect.call_count, 1)
device.set_configuration(fan_mode=FanMode.FAN,
Expand Down Expand Up @@ -596,7 +596,7 @@ def test_set_configuration_timer(self, mocked_connect, mocked_publish):
device.connection_callback(True)
device.state_data_available()
device.sensor_data_available()
connected = device.connect(None)
connected = device.auto_connect()
self.assertTrue(connected)
self.assertEqual(mocked_connect.call_count, 1)
device.set_configuration(sleep_timer=10)
Expand Down Expand Up @@ -632,7 +632,7 @@ def test_set_configuration_timer_off(self, mocked_connect, mocked_publish):
device.connection_callback(True)
device.state_data_available()
device.sensor_data_available()
connected = device.connect(None)
connected = device.auto_connect()
self.assertTrue(connected)
self.assertEqual(mocked_connect.call_count, 1)
device.set_configuration(sleep_timer=0)
Expand Down Expand Up @@ -667,7 +667,7 @@ def test_dont_set_configuration_if_not_connected(self, mocked_connect,
device._current_state = DysonPureCoolState(
open("tests/data/state.json", "r").read())
device.connection_callback(False)
connected = device.connect(None)
connected = device.auto_connect()
self.assertFalse(connected)
self.assertEqual(mocked_connect.call_count, 1)
device.set_configuration(fan_mode=FanMode.FAN,
Expand Down

0 comments on commit 58c1fa9

Please sign in to comment.