Esempio n. 1
0
def run_pytradfri():
    api_factory = APIFactory('192.168.1.123', 'myUserName',
                             'password123456789')
    api = api_factory.request

    gateway = Gateway()

    devices_command = gateway.get_devices()
    devices_commands = yield from api(devices_command)
    devices = yield from api(devices_commands)

    groups_command = gateway.get_groups()
    groups_commands = yield from api(groups_command)
    groups = yield from api(groups_commands)

    for device in devices:
        observe_command = device.observe(observe_device_callback, observe_err_callback, duration=0)
        # Start observation as a second task on the loop.
        ensure_future(api(observe_command))
        yield from asyncio.sleep(0)

    for group in groups:
        observe_command = group.observe(observe_group_callback, observe_err_callback, duration=0)
        # Start observation as a second task on the loop.
        ensure_future(api(observe_command))
        yield from asyncio.sleep(0)

    # Sleep in an infinite loop to keep this running but also allow other tasks to execute
    while True:
        yield from asyncio.sleep(1)
Esempio n. 2
0
async def async_setup_entry(hass, entry):
    """Create a gateway."""
    # host, identity, key, allow_tradfri_groups
    tradfri_data = hass.data.setdefault(DOMAIN, {})[entry.entry_id] = {}
    listeners = tradfri_data[LISTENERS] = []

    factory = await APIFactory.init(
        entry.data[CONF_HOST],
        psk_id=entry.data[CONF_IDENTITY],
        psk=entry.data[CONF_KEY],
    )

    async def on_hass_stop(event):
        """Close connection when hass stops."""
        await factory.shutdown()

    listeners.append(
        hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, on_hass_stop))

    api = factory.request
    gateway = Gateway()

    try:
        gateway_info = await api(gateway.get_gateway_info())
        devices_commands = await api(gateway.get_devices())
        devices = await api(devices_commands)
        groups_commands = await api(gateway.get_groups())
        groups = await api(groups_commands)
    except RequestError as err:
        await factory.shutdown()
        raise ConfigEntryNotReady from err

    tradfri_data[KEY_API] = api
    tradfri_data[FACTORY] = factory
    tradfri_data[DEVICES] = devices
    tradfri_data[GROUPS] = groups

    dev_reg = await hass.helpers.device_registry.async_get_registry()
    dev_reg.async_get_or_create(
        config_entry_id=entry.entry_id,
        connections=set(),
        identifiers={(DOMAIN, entry.data[CONF_GATEWAY_ID])},
        manufacturer=ATTR_TRADFRI_MANUFACTURER,
        name=ATTR_TRADFRI_GATEWAY,
        # They just have 1 gateway model. Type is not exposed yet.
        model=ATTR_TRADFRI_GATEWAY_MODEL,
        sw_version=gateway_info.firmware_version,
    )

    for component in PLATFORMS:
        hass.async_create_task(
            hass.config_entries.async_forward_entry_setup(entry, component))

    return True
Esempio n. 3
0
def connect():
	print("connect")
	global conf
	global api_factory	
	global lights
	global groups
	global api
	try:
		identity = conf[ip_host].get('identity')
		psk = conf[ip_host].get('key')
		api_factory = APIFactory(host=ip_host, psk_id=identity, psk=psk)
	except KeyError:
		identity = uuid.uuid4().hex
		api_factory = APIFactory(host=ip_host, psk_id=identity)

		try:
			psk = api_factory.generate_psk(key)
			print('Generated PSK: ', psk)

			conf[ip_host] = {'identity': identity,'key': psk}
			save_json(CONFIG_FILE, conf)
		except AttributeError:
			raise PytradfriError("Please provide the 'Security Code' on the back of your Tradfri gateway using the -K flag.")

	api = api_factory.request
	gateway = Gateway()

	#get all devices
	devices_command = gateway.get_devices()
	devices_commands = api(devices_command)
	devices = api(devices_commands)
	# create list of available bulbs
	lamps = [dev for dev in devices if dev.has_light_control]

	# get all available groups
	groups_command = gateway.get_groups()
	groups_commands = api(groups_command)
	groupc = api(groups_commands)
	groups = [dev for dev in groupc]
	
	lights = [dev for dev in devices if dev.has_light_control]
Esempio n. 4
0
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Create a gateway."""
    # host, identity, key, allow_tradfri_groups
    tradfri_data: dict[str, Any] = {}
    hass.data.setdefault(DOMAIN, {})[entry.entry_id] = tradfri_data
    listeners = tradfri_data[LISTENERS] = []

    factory = await APIFactory.init(
        entry.data[CONF_HOST],
        psk_id=entry.data[CONF_IDENTITY],
        psk=entry.data[CONF_KEY],
    )

    async def on_hass_stop(event):
        """Close connection when hass stops."""
        await factory.shutdown()

    listeners.append(hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, on_hass_stop))

    api = factory.request
    gateway = Gateway()

    try:
        gateway_info = await api(gateway.get_gateway_info())
        devices_commands = await api(gateway.get_devices())
        devices = await api(devices_commands)
        groups_commands = await api(gateway.get_groups())
        groups = await api(groups_commands)
    except RequestError as err:
        await factory.shutdown()
        raise ConfigEntryNotReady from err

    tradfri_data[KEY_API] = api
    tradfri_data[FACTORY] = factory
    tradfri_data[DEVICES] = devices
    tradfri_data[GROUPS] = groups

    dev_reg = await hass.helpers.device_registry.async_get_registry()
    dev_reg.async_get_or_create(
        config_entry_id=entry.entry_id,
        connections=set(),
        identifiers={(DOMAIN, entry.data[CONF_GATEWAY_ID])},
        manufacturer=ATTR_TRADFRI_MANUFACTURER,
        name=ATTR_TRADFRI_GATEWAY,
        # They just have 1 gateway model. Type is not exposed yet.
        model=ATTR_TRADFRI_GATEWAY_MODEL,
        sw_version=gateway_info.firmware_version,
    )

    hass.config_entries.async_setup_platforms(entry, PLATFORMS)

    async def async_keep_alive(now):
        if hass.is_stopping:
            return

        try:
            await api(gateway.get_gateway_info())
        except RequestError:
            _LOGGER.error("Keep-alive failed")

    listeners.append(
        async_track_time_interval(hass, async_keep_alive, timedelta(seconds=60))
    )

    return True
Esempio n. 5
0
class RequestHandler(BaseHTTPRequestHandler):
    key = None
    hubip = None

    BAD_REQUEST = -1
    SUCCESS = 0

    # these values are not double-checked
    # if any mistakes are made here, things might blow up in your face
    COLOR = 'color'
    SWITCH = 'switch'
    BRIGHTNESS = 'brightness'

    # these values are the specific ones that the white spectrum tradfri bulbs use
    # they should not be changed, since the bulbs physically can't display other colors
    # i haven't tested the full-spectrum bulbs, but they should presumably support any color
    COLOR_TO_HEX_MAP = {
        'warm': 'efd275',
        'orange': 'efd275',
        'red': 'efd275',

        'normal': 'f1e0b5',
        'yellow': 'f1e0b5',

        'cool': 'f5faf6',
        'cold': 'f5faf6',
        'white': 'f5faf6',
        'blue': 'f5faf6'
    }
    COMMAND_PART_TYPE_TO_VALUES = {
        COLOR: list(COLOR_TO_HEX_MAP.keys()),
        SWITCH: ['on', 'off'],
        BRIGHTNESS: list(str(i) for i in range(101))
    }

    ZONES = ['living', 'living room', 'bathroom', 'bedroom', 'office']
    ZONE_ALIAS_MAP = {
        'living room': 'Living Room',
        'living': 'Living Room',
        'bedroom': 'Bedroom',
        'bathroom': 'Bathroom',
        'office': 'Office'
    }
    # ?[zone] [on|off]
    # ?[zone] [color]
    # ?[zone] [brightness]
    # ?[zone] [color] [brightness]
    # ?[zone] [brightness] [color]
    FORMATS = [
        [SWITCH],
        [COLOR],
        [BRIGHTNESS],
        [COLOR, BRIGHTNESS],
        [BRIGHTNESS, COLOR]
    ]

    # def __init__(self, request, client_address, server):
    #     BaseHTTPRequestHandler.__init__(self, request, client_address, server)
    #     # print("hub" + str(self.hubip))

    def init(self):
        if self.hubip is None:
            conf = configparser.ConfigParser()
            conf.read('tradfri.cfg')
            #print(conf)

            self.hubip = conf.get('tradfri', 'hubip')
            self.securityid = conf.get('tradfri', 'securityid')
            self.api = api_factory(self.hubip, self.securityid)
            self.gateway = Gateway()

            groups_command = self.gateway.get_groups()
            groups_commands = self.api(groups_command)
            groups = self.api(*groups_commands)
            self.groups = dict((g.name, g) for g in groups)
            print(str(self.groups))

    def add_zone(self, zone_ids, inverted, new_zone):
        if inverted:
            zone_ids.remove(self.ZONE_ALIAS_MAP[new_zone])
        else:
            zone_ids.add(self.ZONE_ALIAS_MAP[new_zone])
        return zone_ids

    def _parse_request(self):
        #print("hub2" + self.hubip)
        self.init()

        parsed_req = urlparse(self.path)
        args = parse_qs(parsed_req.query)
        if self.headers.get('content-type', '') \
            == 'application/x-www-form-urlencoded':
                body = self.rfile.read(int(self.headers.get('content-length')))
                args = parse_qs(body)

        args = dict((k, v[0]) for k, v in args.items())
        return (parsed_req.path, args)

    def isvalid(self, cmd, format):
        for i in range(len(format)):
            part_type = format[i]
            part = cmd[i]
            for acceptable_value in self.COMMAND_PART_TYPE_TO_VALUES[part_type]:
                if part.lower() == acceptable_value.lower():
                    break
            else:
                print("invalid: " + str(cmd) + " against " + str(format))
                return False
        print("valid: " + str(cmd) + " against " + str(format))
        return True

    def run_command(self, zone_ids, cmd, format):
        print("cmd:" + str(cmd))
        print("format:" + str(format))

        # zones = list(self.ZONES)
        # if zone_ is not None:
        #     zones = [zone_]
        print("zone_ids: " + str(zone_ids))

        for i in range(len(format)):
            part_type = format[i]
            part = cmd[i].lower()
            #zone_ids = set(self.ZONE_ALIAS_MAP[zone] for zone in zones)
            #print("zone ids: " + str(zone_ids))
            #for zone in zones:
            for zone_id in zone_ids:
                #zone_id = self.ZONE_ALIAS_MAP[zone]
                if part_type == self.SWITCH:
                    # print('performing now')
                    # print('hub ip is ' + str(type(self.hubip)))
                    # print('key is ' + str(type(self.securityid)))
                    # print('zone id is ' + str(type(zone_id)))
                    # print('part is ' + str(type(part)))
                    self.api(self.groups[zone_id].set_state(1 if part == 'on' else 0))
                    # print('done')
                elif part_type == self.COLOR:
                    # need to do it per light...
                    for devcmd in self.groups[zone_id].members():
                        dev = self.api(devcmd)
                        print(str(dev) + ": " + str(dev.has_light_control))
                        if not dev.has_light_control:
                            continue
                        self.api(dev.light_control.set_hex_color(self.COLOR_TO_HEX_MAP[part]))
                    # self.groups[zone_id].set_hex_color(self.COLOR_TO_HEX_MAP[part])
                elif part_type == self.BRIGHTNESS:
                    rawval = int(float(part) * 2.55)
                    self.api(self.groups[zone_id].set_dimmer(rawval))
                    if rawval > 0:
                        self.api(self.groups[zone_id].set_state(1))
                        #sleep(0.2)
                #sleep(0.2)

        return self.SUCCESS

    def process(self, input):
        command = input.lower().split(' ')
        # print(str(command))
        zone_ids = set()
        inverted = False

        if len(command) == 0:
            return self.BAD_REQUEST

        if command[0] == 'except': # magic "invert" keyword
            zone_ids = set(self.ZONE_ALIAS_MAP.values())
            inverted = True
            command = command[1:]

        if len(command) >= 3 and command[0] + ' ' + command[1] in self.ZONES: # hacky support for two-word zone names
            #zones.append(command[0] + ' ' + command[1])
            self.add_zone(zone_ids, inverted, command[0] + ' ' + command[1])
            command = command[2:]

        if command[0] in self.ZONES:
            #zones.append(command[0])
            self.add_zone(zone_ids, inverted, command[0])
            command = command[1:]

        if len(command) == 0:
            return self.BAD_REQUEST
        
        if len(zone_ids) == 0:
            zone_ids = set(self.ZONE_ALIAS_MAP.values())

        for format in self.FORMATS:
            if len(format) == len(command) and self.isvalid(command, format):
                return self.run_command(zone_ids, command, format)
        return self.BAD_REQUEST

    # def do_POST(self):
    #     path, args = self._parse_request()
    #     self.do('POST', path, args)

    def do_GET(self):
        path, args = self._parse_request()
        self.do('GET', path, args)

    def do(self, method, path, args):
        if args.get('key') != RequestHandler.key or 'command' not in args:
            self.send_error(400, 'Bad Request')
            return

        retval = self.process(args['command'].strip())

        if retval == self.SUCCESS:
            self.send_response(200)
            self.end_headers()
        elif retval == self.BAD_REQUEST:
            self.send_error(400, 'Bad request')
        else:
            self.send_error(500, 'Trigger command failed')
Esempio n. 6
0
	print(str(datetime.datetime.now().time())[:8] + " "+ str(x))
	sys.stdout.flush()
	
api = api_factory.request

gateway = Gateway()

#get all devices
devices_command = gateway.get_devices()
devices_commands = api(devices_command)
devices = api(devices_commands)
# create list of available bulbs
lamps = [dev for dev in devices if dev.has_light_control]

# get all available groups
groups_command = gateway.get_groups()
groups_commands = api(groups_command)
groupc = api(groups_commands)
groups = [dev for dev in groupc]
	
lights = [dev for dev in devices if dev.has_light_control]
#-------------------------------------------------------------------
	
# supported_features 1=mono 23=color
#device info  TRADFRI bulb E27 W opal 1000lm
#device info  TRADFRI bulb E27 opal 1000lm
#device info  TRADFRI bulb E27 opal 1000lm
#device info  TRADFRI bulb GU10 WS 400lm
#device info  TRADFRI bulb GU10 WS 400lm
#device info  TRADFRI bulb GU10 WS 400lm
#device info  LCT001
Esempio n. 7
0
class MainWindow(QWidget):
    def __init__(self, appctx):
        super().__init__()

        self.appctx = appctx
        self.api = None
        self.settings = Settings()
        self.gateway = Gateway()
        self.timers: Dict[str, QTimer] = {}

        self.init_ui()

    def init_ui(self):
        self.vbox = QVBoxLayout()
        self.hbox = QHBoxLayout()

        # Set layout
        self.setLayout(self.vbox)

        # Group list
        vbox3 = QVBoxLayout()
        group_frame = QGroupBox("Device Groups")
        group_frame.setLayout(QVBoxLayout())
        self.group_list = QListWidget()
        self.group_list.itemPressed.connect(self.group_selected)
        group_frame.layout().addWidget(self.group_list)
        vbox3.addWidget(group_frame)

        # Sliders
        self.group_toggle = QCheckBox("Power")
        self.group_toggle.setEnabled(False)
        vbox3.addWidget(self.group_toggle)
        vbox3.addWidget(QLabel("Brightness"))
        self.group_brightness_slider = QSlider(Qt.Orientation.Horizontal)
        self.group_brightness_slider.setEnabled(False)
        self.group_brightness_slider.sliderMoved.connect(
            self.group_brightness_changed)
        vbox3.addWidget(self.group_brightness_slider)
        vbox3.addWidget(QLabel("Color Temperature"))
        self.group_color_slider = QSlider(Qt.Orientation.Horizontal)
        self.group_color_slider.setEnabled(False)
        self.group_color_slider.sliderMoved.connect(self.group_color_changed)
        vbox3.addWidget(self.group_color_slider)

        self.hbox.addLayout(vbox3)

        # moods
        mood_frame = QGroupBox("Moods")
        mood_frame.setLayout(QVBoxLayout())
        self.mood_list = QListWidget()
        self.mood_list.itemPressed.connect(self.mood_selected)
        mood_frame.layout().addWidget(self.mood_list)

        self.hbox.addWidget(mood_frame)

        # Devices in group
        vbox2 = QVBoxLayout()

        device_frame = QGroupBox("Devices in Group")
        device_frame.setLayout(QVBoxLayout())
        self.device_list = QListWidget()
        self.device_list.setEnabled(False)
        self.device_list.itemPressed.connect(self.device_selected)
        device_frame.layout().addWidget(self.device_list)
        vbox2.addWidget(device_frame)

        # Sliders
        self.device_toggle = QCheckBox("Power")
        self.device_toggle.setEnabled(False)
        vbox2.addWidget(self.device_toggle)
        vbox2.addWidget(QLabel("Brightness"))
        self.brightness_slider = QSlider(Qt.Orientation.Horizontal)
        self.brightness_slider.setEnabled(False)
        self.brightness_slider.sliderMoved.connect(self.brightness_changed)
        vbox2.addWidget(self.brightness_slider)
        vbox2.addWidget(QLabel("Color Temperature"))
        self.color_slider = QSlider(Qt.Orientation.Horizontal)
        self.color_slider.setEnabled(False)
        self.color_slider.sliderMoved.connect(self.color_changed)
        vbox2.addWidget(self.color_slider)

        self.hbox.addLayout(vbox2)
        self.vbox.addLayout(self.hbox)

        # Settings button
        icon = QIcon(resource_path('icons/settings.png'))
        self.settings_button = QPushButton(icon, "Settings")
        self.settings_button.pressed.connect(self.settings_pressed)
        self.vbox.addWidget(self.settings_button)

        self.setWindowTitle('TradfriGUI')
        self.re_init()

    def re_init(self):
        if self.settings.gateway_ip is None or self.settings.gateway_ip == '':
            self.settings_pressed()
        self.api = get_api(self.settings)

        self.device_list.clear()
        self.group_list.clear()

        if self.api is None:
            return

        groups = self.api(self.gateway.get_groups())
        if len(groups) == 0:
            self.group_list.setEnabled(False)
            # TODO: load devices directly

        for group in groups:
            item = self.api(group)
            list_item = QListWidgetItem(item.name, self.group_list)
            setattr(list_item, 'api_item', item)

    def group_selected(self):
        current_item = self.group_list.currentItem()
        item = getattr(current_item, 'api_item', None)
        if item is None:
            return
        # refresh from gateway
        item = self.api(self.gateway.get_group(item.id))

        # load moods
        self.mood_list.clear()
        moods = self.api(item.moods())
        for m in moods:
            mood = self.api(m)
            list_item = QListWidgetItem(mood.name, self.mood_list)
            setattr(list_item, 'api_item', mood)

        # load devices
        devices = item.members()
        self.device_list.clear()

        # determine shared state and add devices to list
        state = False
        color_temp = False
        min_color = 10000
        max_color = 0
        color = []
        brightness = []
        for d in devices:
            device = self.api(d)
            if device.has_light_control:
                if device.light_control.lights[0].state:
                    state = True
                if device.light_control.can_set_dimmer:
                    if device.light_control.lights[0].state:
                        brightness.append(
                            device.light_control.lights[0].dimmer)
                    else:
                        brightness.append(0)
                if device.light_control.can_set_temp:
                    color_temp = True
                    min_color = min(min_color, device.light_control.min_mireds)
                    max_color = max(max_color, device.light_control.max_mireds)
                    color.append(device.light_control.lights[0].color_temp)
            list_item = QListWidgetItem(device.name, self.device_list)
            setattr(list_item, 'api_item', device)

        if len(brightness) > 0:
            brightness = int(sum(brightness) / len(brightness))
        else:
            brightness = 0

        if len(color) > 0:
            color = int(sum(color) / len(color))
        else:
            color = min_color

        # enable device list and controls
        self.device_list.setEnabled(True)

        self.group_brightness_slider.setEnabled(True)
        self.group_brightness_slider.setMinimum(0)
        self.group_brightness_slider.setMaximum(254)
        self.group_brightness_slider.setSingleStep(16)
        self.group_brightness_slider.setValue(brightness)

        if color_temp:
            self.group_color_slider.setEnabled(True)
            self.group_color_slider.setMinimum(min_color)
            self.group_color_slider.setMaximum(max_color)
            self.group_color_slider.setSingleStep(
                int((max_color - min_color) / 10))
            self.group_color_slider.setValue(color)
        else:
            self.group_color_slider.setEnabled(False)

        self.group_toggle.setEnabled(True)
        try:
            self.group_toggle.stateChanged.disconnect(self.group_toggled)
        except RuntimeError:
            pass  # Disconnect failed because nothing was connected
        self.group_toggle.setCheckState(
            Qt.CheckState.Checked if state else Qt.CheckState.Unchecked)
        self.group_toggle.stateChanged.connect(self.group_toggled)

        self.brightness_slider.setEnabled(False)
        self.color_slider.setEnabled(False)
        self.device_toggle.setEnabled(False)

    def device_selected(self):
        current_item = self.device_list.currentItem()
        item = getattr(current_item, 'api_item', None)
        if item is None:
            return
        # refresh from gateway
        item = self.api(self.gateway.get_device(item.id))

        # enable appropriate controls
        if item.has_light_control:
            ctrl = item.light_control
            if ctrl.can_set_dimmer:
                self.brightness_slider.setEnabled(True)
                self.brightness_slider.setMinimum(0)
                self.brightness_slider.setMaximum(254)
                self.brightness_slider.setSingleStep(16)
                self.brightness_slider.setValue(ctrl.lights[0].dimmer)
            else:
                self.brightness_slider.setEnabled(False)
            if ctrl.can_set_temp:
                self.color_slider.setEnabled(True)
                self.color_slider.setMinimum(ctrl.min_mireds)
                self.color_slider.setMaximum(ctrl.max_mireds)
                self.color_slider.setSingleStep(
                    int((ctrl.max_mireds - ctrl.min_mireds) / 10))
                self.color_slider.setValue(ctrl.lights[0].color_temp)
            else:
                self.color_slider.setEnabled(False)
            self.device_toggle.setEnabled(True)
            try:
                self.device_toggle.stateChanged.disconnect(self.device_toggled)
            except RuntimeError:
                pass  # disconnect failed because nothing was connected
            self.device_toggle.setCheckState(
                Qt.CheckState.Checked if ctrl.lights[0].state else Qt.
                CheckState.Unchecked)
            self.device_toggle.stateChanged.connect(self.device_toggled)
        else:
            self.brightness_slider.setEnabled(False)
            self.color_slider.setEnabled(False)
            self.device_toggle.setEnabled(False)

    def mood_selected(self):
        current_group = self.group_list.currentItem()
        group = getattr(current_group, 'api_item', None)
        if group is None:
            return
        # refresh from gateway
        group = self.api(self.gateway.get_group(group.id))

        current_mood = self.mood_list.currentItem()
        mood = getattr(current_mood, 'api_item', None)
        if mood is None:
            return

        self.api(group.activate_mood(mood.id))

    def group_brightness_changed(self):
        current_item = self.group_list.currentItem()
        if current_item is None:
            return
        item = getattr(current_item, 'api_item', None)
        command = item.set_dimmer(self.group_brightness_slider.value(),
                                  transition_time=2)

        self.queue_command('group_brightness', command)

    def group_color_changed(self):
        current_item = self.group_list.currentItem()
        if current_item is None:
            return
        item = getattr(current_item, 'api_item', None)

        command = item.set_color_temp(self.group_color_slider.value(),
                                      transition_time=2)

        self.queue_command('group_color', command)

    def brightness_changed(self):
        current_item = self.device_list.currentItem()
        if current_item is None:
            return
        item = getattr(current_item, 'api_item', None)
        command = item.light_control.set_dimmer(self.brightness_slider.value(),
                                                transition_time=2)

        self.queue_command('device_brightness_{}'.format(item.id), command)

    def color_changed(self):
        current_item = self.device_list.currentItem()
        if current_item is None:
            return
        item = getattr(current_item, 'api_item', None)
        command = item.light_control.set_color_temp(self.color_slider.value(),
                                                    transition_time=2)

        self.queue_command('device_color_{}'.format(item.id), command)

    def device_toggled(self):
        current_item = self.device_list.currentItem()
        if current_item is None:
            return
        item = getattr(current_item, 'api_item', None)
        command = item.light_control.set_state(
            self.device_toggle.checkState() == Qt.CheckState.Checked)
        self.api(command)

    def group_toggled(self):
        current_item = self.group_list.currentItem()
        if current_item is None:
            return
        item = getattr(current_item, 'api_item', None)
        command = item.set_state(
            self.group_toggle.checkState() == Qt.CheckState.Checked)
        self.api(command)

    def settings_pressed(self):
        config = ConfigWindow(self.appctx, self)
        config.setWindowModality(Qt.ApplicationModal)
        config.exec_()

        # reload settings
        self.settings = config.settings

        # re-initialize window
        self.re_init()

    def queue_command(self, name, command):
        timer = self.timers.get(name, None)
        if timer is None:
            timer = QTimer()
            timer.setInterval(200)
            timer.setSingleShot(True)
            timer.timeout.connect(self.timeout)
            timer.start()

        setattr(timer, 'command', command)
        self.timers[name] = timer

    def timeout(self):
        remove = []
        for key, item in self.timers.items():
            if item.isActive() == False:
                cmd = getattr(item, 'command')
                self.api(cmd)
                remove.append(key)
        for key in remove:
            del self.timers[key]
Esempio n. 8
0
                        base_name + "/" + str(blind.id) + battery_name,
                        blind.device_info.battery_level)
                    if blind.blind_control.blinds[
                            0].current_cover_position >= 50.0:
                        cp = ON
                    else:
                        cp = OFF
                    if cp:
                        client.publish(
                            base_name + "/" + str(blind.id) + status_name, cp)
            else:
                print("No devices")
                client.publish("esp/text", "tradfri: no devices")

            try:
                groups_command = gateway.get_groups()
                groups_commands = api(groups_command)
                groups = api(groups_commands)
                #print(groups)
                last_time = time.time()
            except:
                client.disconnect()
                client.reconnect()
                client.publish("esp/text",
                               "tradfri: error while getting groups")
                print("error groups")
                continue
                #pass
            time.sleep(SLEEP)
            if groups:
                print("Id\tState\tDimmer\tName")
Esempio n. 9
0
async def async_setup_entry(
    hass: HomeAssistant,
    entry: ConfigEntry,
) -> bool:
    """Create a gateway."""
    tradfri_data: dict[str, Any] = {}
    hass.data.setdefault(DOMAIN, {})[entry.entry_id] = tradfri_data
    listeners = tradfri_data[LISTENERS] = []

    factory = await APIFactory.init(
        entry.data[CONF_HOST],
        psk_id=entry.data[CONF_IDENTITY],
        psk=entry.data[CONF_KEY],
    )
    tradfri_data[FACTORY] = factory  # Used for async_unload_entry

    async def on_hass_stop(event: Event) -> None:
        """Close connection when hass stops."""
        await factory.shutdown()

    # Setup listeners
    listeners.append(
        hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, on_hass_stop))

    api = factory.request
    gateway = Gateway()
    groups: list[Group] = []

    try:
        gateway_info = await api(gateway.get_gateway_info(),
                                 timeout=TIMEOUT_API)
        devices_commands: Command = await api(gateway.get_devices(),
                                              timeout=TIMEOUT_API)
        devices: list[Device] = await api(devices_commands,
                                          timeout=TIMEOUT_API)

        if entry.data[CONF_IMPORT_GROUPS]:
            # Note: we should update this page when deprecating:
            # https://www.home-assistant.io/integrations/tradfri/
            _LOGGER.warning(
                "Importing of Tradfri groups has been deprecated due to stability issues "
                "and will be removed in Home Assistant core 2022.4")
            # No need to load groups if the user hasn't requested it
            groups_commands: Command = await api(gateway.get_groups(),
                                                 timeout=TIMEOUT_API)
            groups = await api(groups_commands, timeout=TIMEOUT_API)

    except RequestError as exc:
        await factory.shutdown()
        raise ConfigEntryNotReady from exc

    dev_reg = await hass.helpers.device_registry.async_get_registry()
    dev_reg.async_get_or_create(
        config_entry_id=entry.entry_id,
        connections=set(),
        identifiers={(DOMAIN, entry.data[CONF_GATEWAY_ID])},
        manufacturer=ATTR_TRADFRI_MANUFACTURER,
        name=ATTR_TRADFRI_GATEWAY,
        # They just have 1 gateway model. Type is not exposed yet.
        model=ATTR_TRADFRI_GATEWAY_MODEL,
        sw_version=gateway_info.firmware_version,
    )

    remove_stale_devices(hass, entry, devices)

    # Setup the device coordinators
    coordinator_data = {
        CONF_GATEWAY_ID: gateway,
        KEY_API: api,
        COORDINATOR_LIST: [],
        GROUPS_LIST: [],
    }

    for device in devices:
        coordinator = TradfriDeviceDataUpdateCoordinator(hass=hass,
                                                         api=api,
                                                         device=device)
        await coordinator.async_config_entry_first_refresh()

        entry.async_on_unload(
            async_dispatcher_connect(hass, SIGNAL_GW,
                                     coordinator.set_hub_available))
        coordinator_data[COORDINATOR_LIST].append(coordinator)

    for group in groups:
        group_coordinator = TradfriGroupDataUpdateCoordinator(hass=hass,
                                                              api=api,
                                                              group=group)
        await group_coordinator.async_config_entry_first_refresh()
        entry.async_on_unload(
            async_dispatcher_connect(hass, SIGNAL_GW,
                                     group_coordinator.set_hub_available))
        coordinator_data[GROUPS_LIST].append(group_coordinator)

    tradfri_data[COORDINATOR] = coordinator_data

    async def async_keep_alive(now: datetime) -> None:
        if hass.is_stopping:
            return

        gw_status = True
        try:
            await api(gateway.get_gateway_info())
        except RequestError:
            _LOGGER.error("Keep-alive failed")
            gw_status = False

        async_dispatcher_send(hass, SIGNAL_GW, gw_status)

    listeners.append(
        async_track_time_interval(hass, async_keep_alive,
                                  timedelta(seconds=60)))

    hass.config_entries.async_setup_platforms(entry, PLATFORMS)

    return True
Esempio n. 10
0
class TradfriManager(metaclass=Singleton):

    api_factory = None
    api = None
    gateway = None
    enabled = False
    initialized = False
    last_init = 0

    def __init__(self):
        self.tradfri_state = TradfriState()
        self.observing_end = 0
        self.observing = False
        self.observe_thread = None

    def init(self):
        if self.initialized:
            Logger().write(LogVerbosity.Info, "already init")
            return

        if sys.platform != "linux" and sys.platform != "linux2":
            Logger().write(LogVerbosity.Info, "Lighting: Not initializing, no coap client available on windows")
            self.initialized = True
            self.tradfri_state.update_group(DeviceGroup(1, "Test group", True, 128, 6))
            self.tradfri_state.update_group(DeviceGroup(2, "Test group 2", False, 18, 6))
            return

        if current_time() - self.last_init < 5000:
            Logger().write(LogVerbosity.Info, "Tried initialization less than 5s ago")
            return

        Logger().write(LogVerbosity.All, "Start LightManager init")
        self.enabled = True
        if not self.initialized:
            ip = Settings.get_string("tradfri_hub_ip")
            identity = Database().get_stat_string("LightingId")
            key = Database().get_stat_string("LightingKey")

            if identity is None or key is None:
                Logger().write(LogVerbosity.Info, "Lighting: No identity/key found, going to generate new")
                # We don't have all information to connect, reset and start from scratch
                Database().remove_stat("LightingId")
                Database().remove_stat("LightingKey")
                key = None

                identity = uuid.uuid4().hex
                Database().update_stat("LightingId", identity)  # Generate and save a new id
                self.api_factory = APIFactory(host=ip, psk_id=identity)
            else:
                self.api_factory = APIFactory(host=ip, psk_id=identity, psk=key)

            self.api = self.api_factory.request
            self.gateway = Gateway()

            if key is None:
                try:
                    security_code = SecureSettings.get_string("tradfri_hub_code")  # the code at the bottom of the hub
                    key = self.api_factory.generate_psk(security_code)
                    Database().update_stat("LightingKey", key)  # Save the new key
                    Logger().write(LogVerbosity.Info, "Lighting: New key retrieved")
                except Exception as e:
                    Logger().write_error(e, "Unhandled exception")
                    return
            else:
                Logger().write(LogVerbosity.Info, "Lighting: Previously saved key found")

            try:
                self.initialized = True
                groups = self.get_device_groups()
                for group in groups:
                    self.tradfri_state.update_group(group)
            except Exception as e:
                Logger().write(LogVerbosity.Info, "Failed to init tradfri, clearing previous key to try generate new")
                self.initialized = False
                Database().remove_stat("LightingId")
                Database().remove_stat("LightingKey")
                Logger().write_error(e, "Failed to get groups from hub")

    def start_observing(self):
        Logger().write(LogVerbosity.Debug, "Start observing light data")
        self.observing = True
        if self.observing_end > current_time():
            Logger().write(LogVerbosity.All, "Still observing, not starting again")
            return  # still observing, the check observing thread will renew

        if not self.check_state():
            return

        self.observing_end = current_time() + 30000
        groups_commands = self.api(self.gateway.get_groups())
        result = self.api(groups_commands)
        for group in result:
            self.observe_group(group)

    def observe_group(self, group):
        Logger().write(LogVerbosity.All, "Starting observe for group " + group.name)
        self.observe_thread = CustomThread(lambda: self.api(group.observe(
            self.tradfri_state.update_group,
            lambda x: self.check_observe(group), duration=30)), "Light group observer", [])
        self.observe_thread.start()

    def check_observe(self, group):
        if self.observing:
            # Restart observing since it timed out
            Logger().write(LogVerbosity.Debug, "Restarting observing for group " + str(group.name))
            self.observe_group(group)

    def stop_observing(self):
        Logger().write(LogVerbosity.Debug, "Stop observing light data")
        self.observing = False

    def get_devices(self):
        if not self.check_state():
            return []

        Logger().write(LogVerbosity.All, "Get devices")
        devices_commands = self.api(self.gateway.get_devices())
        devices = self.api(devices_commands)
        return [d for d in [self.parse_device(x) for x in devices] if d is not None]

    def set_state(self, device_id, state):
        if not self.check_state():
            return

        Logger().write(LogVerbosity.All, "Set device state")
        device = self.api(self.gateway.get_device(device_id))
        if device.has_light_control:
            self.api(device.light_control.set_state(state))
        else:
            self.api(device.socket_control.set_state(state))

    def set_light_warmth(self, device_id, warmth):
        if not self.check_state():
            return

        Logger().write(LogVerbosity.All, "Set light warmth")
        device = self.api(self.gateway.get_device(device_id))
        self.api(device.light_control.set_color_temp(warmth))

    def set_light_dimmer(self, device_id, amount):
        if not self.check_state():
            return

        Logger().write(LogVerbosity.All, "Set light dimmer")
        device = self.api(self.gateway.get_device(device_id))
        self.api(device.light_control.set_dimmer(amount))

    def set_device_name(self, device_id, name):
        if not self.check_state():
            return

        Logger().write(LogVerbosity.All, "Set device name")
        device = self.api(self.gateway.get_device(device_id))
        self.api(device.set_name(name))

    def get_device_groups(self):
        if not self.check_state():
            return []

        Logger().write(LogVerbosity.All, "Get device groups")
        groups_commands = self.api(self.gateway.get_groups())
        result = self.api(groups_commands)
        Logger().write(LogVerbosity.All, "Get device groups: " + str([x.raw for x in result]))
        return [DeviceGroup(group.id, group.name, group.state, group.dimmer, len(group.member_ids)) for group in result]

    def get_devices_in_group(self, group):
        if not self.check_state():
            return []

        Logger().write(LogVerbosity.All, "Get lights in group")
        group = self.api(self.gateway.get_group(group))
        members = group.member_ids
        result = [self.api(self.gateway.get_device(x)) for x in members]
        return [d for d in [self.parse_device(x) for x in result] if d is not None]

    def set_group_name(self, group, name):
        if not self.check_state():
            return

        Logger().write(LogVerbosity.All, "Set group name")
        group = self.api(self.gateway.get_group(group))
        self.api(group.set_name(name))

    def set_group_state(self, group, state):
        if not self.check_state():
            return

        Logger().write(LogVerbosity.All, "Set group state")
        group = self.api(self.gateway.get_group(group))
        self.api(group.set_state(state))

    def set_group_dimmer(self, group, dimmer):
        if not self.check_state():
            return

        Logger().write(LogVerbosity.All, "Set group dimmer")
        group = self.api(self.gateway.get_group(group))
        self.api(group.set_dimmer(dimmer))

    def check_state(self):
        if not self.enabled:
            return False  # not available

        if not self.initialized:
            self.init()
            if not self.initialized:
                return False  # init failed
        return True

    @staticmethod
    def parse_device(data):
        if data.has_light_control:
            lights = []
            for light in data.light_control.lights:
                lights.append(LightDevice(
                    light.state,
                    light.dimmer,
                    light.color_temp,
                    light.hex_color))

            return LightControl(data.id,
                                data.name,
                                data.application_type,
                                data.last_seen.timestamp(),
                                data.reachable,
                                data.light_control.can_set_dimmer,
                                data.light_control.can_set_temp,
                                data.light_control.can_set_color,
                                lights)

        elif data.has_socket_control:
            sockets = []
            for socket in data.socket_control.sockets:
                sockets.append(SocketDevice(socket.state))

            return SocketControl(data.id, data.name, data.application_type, data.last_seen.timestamp(), data.reachable, sockets)