summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xweahome.py85
1 files changed, 61 insertions, 24 deletions
diff --git a/weahome.py b/weahome.py
index 9aae4c9..5e35fbd 100755
--- a/weahome.py
+++ b/weahome.py
@@ -5,16 +5,17 @@ from enum import Enum
from argparse import ArgumentParser
from functools import partial
import dbus
-from gi.repository import GObject
+from gi.repository import GObject, GLib
from dbus.mainloop.glib import DBusGMainLoop
-BLUEZ_SERVICE_NAME = 'org.bluez'
-DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager'
-DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties'
+BLUEZ_SERVICE_NAME = 'org.bluez'
+DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager'
+DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties'
-BLUEZ_DEVICE_IFACE = 'org.bluez.Device1'
-GATT_SERVICE_IFACE = 'org.bluez.GattService1'
-GATT_CHAR_IFACE = 'org.bluez.GattCharacteristic1'
+BLUEZ_ADAPTER_IFACE = 'org.bluez.Adapter1'
+BLUEZ_DEVICE_IFACE = 'org.bluez.Device1'
+GATT_SERVICE_IFACE = 'org.bluez.GattService1'
+GATT_CHAR_IFACE = 'org.bluez.GattCharacteristic1'
WEAHOME_SERVICE = '74e7fe00-c6a4-11e2-b7a9-0002a5d5c51b'
DEVINFO_CHAR = '74e78e02-c6a4-11e2-b7a9-0002a5d5c51b'
@@ -41,6 +42,12 @@ def _get_bluez_objects():
obj_manager = bus.get_object(BLUEZ_SERVICE_NAME, '/')
return obj_manager.GetManagedObjects(dbus_interface=DBUS_OM_IFACE)
+def _get_bluez_iface_objs(objects, iface):
+ for path, interfaces in objects.items():
+ if iface in interfaces.keys():
+ obj = bus.get_object(BLUEZ_SERVICE_NAME, path)
+ yield obj, path, interfaces
+
class Event:
__slots__ = ['_observers']
@@ -229,7 +236,10 @@ class WeahomeDevice:
return value / 10.0
def _parse_weather(self, value):
- return WeahomeWeather(value)
+ try:
+ return WeahomeWeather(value)
+ except ValueError:
+ return WeahomeWeather.NO_DATA
def _process_sensor_data_1(self, offset, data):
s0_temperature, s1_temperature, s2_temperature, s3_temperature, \
@@ -452,6 +462,10 @@ class WeahomeDevice:
else:
return "Unknown"
+ @property
+ def address(self):
+ return str(self._get_device_prop("Address"))
+
def connect(self):
self._device.Connect(dbus_interface=BLUEZ_DEVICE_IFACE)
@@ -464,19 +478,16 @@ class WeahomeDevice:
settings.datetime = datetime.datetime.now()
self._write_settings(settings)
-def _is_weahome_device(path):
- device = bus.get_object(BLUEZ_SERVICE_NAME, path)
- uuids = device.Get(BLUEZ_DEVICE_IFACE, 'UUIDs', dbus_interface=DBUS_PROP_IFACE)
+def _is_weahome_device(dbus_obj):
+ uuids = dbus_obj.Get(BLUEZ_DEVICE_IFACE, 'UUIDs', dbus_interface=DBUS_PROP_IFACE)
return WEAHOME_SERVICE in uuids
def scan_for_weahome_devices():
objects = _get_bluez_objects()
devices = []
- for path, interfaces in objects.items():
- if BLUEZ_DEVICE_IFACE not in interfaces.keys():
- continue
- if not _is_weahome_device(path):
+ for obj, path, _ in _get_bluez_iface_objs(objects, BLUEZ_DEVICE_IFACE):
+ if not _is_weahome_device(obj):
continue
device = WeahomeDevice(path)
@@ -484,6 +495,23 @@ def scan_for_weahome_devices():
return devices
+def connect_to_weahome_device(address):
+ address = str(address).upper()
+ objects = _get_bluez_objects()
+
+ # First, find preexisting devices with the same address and return it
+ for obj, path, _ in _get_bluez_iface_objs(objects, BLUEZ_DEVICE_IFACE):
+ device_addr = obj.Get(BLUEZ_DEVICE_IFACE, 'Address', dbus_interface=DBUS_PROP_IFACE)
+ if device_addr == address:
+ device = WeahomeDevice(path)
+ device.connect()
+ return device
+
+ # TODO Adapter1 ConnectDevice is still experimental...
+
+ # No device, no adapters...
+ raise KeyError("Device with address '{0}' not found".format(address))
+
def print_sensor(device, sensor):
print("{0} Sensor {1}:".format(device.name, sensor.name))
if sensor.has_temperature:
@@ -507,12 +535,6 @@ def print_sensor(device, sensor):
if sensor.has_weather:
print(" weather = {0}".format(sensor.weather))
-def disconnect_all_devices():
- print("Disconnecting devices")
- for device in devices:
- if device.connected:
- device.disconnect()
-
# Example client program:
def _connected_changed_cb(sender):
@@ -535,21 +557,36 @@ def _settings_changed_cb(sender):
settings = sender.settings
log.info("{0} Settings: status={1} datetime={2} moon_phase={3} position={4},{5} sun={6},{7} moon={8},{9}".format(sender.name, settings.status, settings.datetime, settings.moon_phase, settings.latitude, settings.longitude, settings.sun_rise, settings.sun_set, settings.moon_rise, settings.moon_set))
+def _disconnect_all_devices():
+ print("Disconnecting devices")
+ for device in devices:
+ if device.connected:
+ device.disconnect()
+
if __name__ == '__main__':
parser = ArgumentParser(description="Weather@home")
+ parser.add_argument("--device", "-d", action='append', help="Connect to specific address")
parser.add_argument("--sync", "-s", action='store_true', help="Sync time")
parser.add_argument("--verbose", "-v", action='store_true', help="Verbose log")
args = parser.parse_args()
- mainloop = GObject.MainLoop()
+ mainloop = GLib.MainLoop()
if args.verbose:
logging.basicConfig(level=logging.DEBUG)
- devices = scan_for_weahome_devices()
+ devices = []
+
+ if args.device:
+ for address in args.device:
+ device = connect_to_weahome_device(address)
+ devices.append(device)
+ else:
+ devices = scan_for_weahome_devices()
+
log.info("Found {0} weather@home devices: {1}".format(len(devices), [dev.name for dev in devices]))
- atexit.register(disconnect_all_devices)
+ atexit.register(_disconnect_all_devices)
for device in devices:
device.connected_changed.observe(_connected_changed_cb)