homehub/packages/homehub_tradfri/homehub_tradfri/services.py

164 lines
4.7 KiB
Python

# -*- coding: utf8 -*-
import asyncio
import logging
import uuid
import aiojobs.aiohttp
from homehub_backend.lib.services import BaseService, ServiceData
from homehub_tradfri.defs import kServiceTradfri
import pytradfri
import pytradfri.api.aiocoap_api
LOGGER = logging.getLogger('homehub.tradfri.services')
class TradfriService(BaseService):
KIND = kServiceTradfri
def __init__(self, app, instance, characteristics):
super(TradfriService, self).__init__(app, instance, characteristics)
self.api_factory = None
self.gateway = None
self.job = None
self.started = False
def state_key(self):
state_key = super(TradfriService, self).state_key()
return '{state_key}.{host}.{key}'.format(
state_key=state_key,
host=self.characteristics['host'],
key=self.characteristics['key'],
)
async def current_data(self):
result = ServiceData()
try:
result.data = {
'groups': await self.get_groups(),
'lights': await self.get_lights(),
}
except Exception as exc:
LOGGER.error('Unhandled exception!', exc_info=exc)
result.exception = exc
return result
async def call_api(self, commands):
api = self.api_factory.request
result = await api(commands)
return result
async def get_lights(self):
lights_command = self.gateway.get_devices()
lights_commands = await self.call_api(lights_command)
result = await self.call_api(lights_commands)
return [
{
'id': light.id,
'name': light.name,
'state': light.light_control.lights[0].state,
'reachable': light.reachable,
'dimmer': light.light_control.lights[0].dimmer,
}
for light in filter(lambda x: x.has_light_control, result)
]
async def get_light(self, light_id):
light_command = self.gateway.get_device(light_id)
light = await self.call_api(light_command)
return light
async def set_light_state(self, light_id, next_state):
light = await self.get_light(light_id)
set_state_command = light.light_control.set_state(next_state, index=0)
await self.call_api(set_state_command)
async def get_groups(self):
groups_command = self.gateway.get_groups()
groups_commands = await self.call_api(groups_command)
result = await self.call_api(groups_commands)
return [
{
'id': group.id,
'name': group.name,
'member_ids': group.member_ids,
}
for group in result
]
async def set_lights_state(self, light_ids, next_state):
_ = await asyncio.gather(*[
self.set_light_state(light_id, next_state)
for light_id in light_ids
])
lights = await self.get_lights()
return list(filter(lambda light: light['id'] in light_ids, lights))
async def worker(self):
while True:
await asyncio.sleep(60)
await self.notify()
if self.job.closed:
break
async def start(self):
if not self.started:
psk_id = None
psk = None
if self.state is not None:
psk_id = self.state.get('psk_id')
psk = self.state.get('psk')
if not psk_id:
psk_id = uuid.uuid4().hex
LOGGER.debug('TradfriService.start() {psk_id} {has_psk} {characteristics}'.format(
psk_id=psk_id,
has_psk=(psk is not None),
characteristics=self.characteristics,
))
self.api_factory = pytradfri.api.aiocoap_api.APIFactory(
host=self.characteristics['host'],
psk_id=psk_id,
psk=psk,
)
if not psk:
psk = await self.api_factory.generate_psk(
self.characteristics['key'],
)
self.gateway = pytradfri.Gateway()
if not self.job:
scheduler = aiojobs.aiohttp.get_scheduler_from_app(self.app)
self.job = await scheduler.spawn(self.worker())
self.set_state({
'psk_id': psk_id,
'psk': psk,
})
self.started = True
async def stop(self):
LOGGER.debug('TradfriService.stop()')
if self.gateway:
self.gateway = None
if self.api_factory:
self.api_factory = None
if self.job is not None and not self.job.closed:
await self.job.close()