Add scene support
This commit is contained in:
parent
bdd6ab840c
commit
071aa7a9ac
14
README.md
14
README.md
@ -13,20 +13,6 @@ I do not guarantee it will work or even that it will not harm your system. I don
|
|||||||
- Hopefully, your Plejd mesh will be auto discovered and you should see a message popping up in your integrations page.
|
- Hopefully, your Plejd mesh will be auto discovered and you should see a message popping up in your integrations page.
|
||||||
- Log in with the credentials you use in the Plejd app when prompted (email address and password)
|
- Log in with the credentials you use in the Plejd app when prompted (email address and password)
|
||||||
|
|
||||||
## Current limitations
|
|
||||||
|
|
||||||
- I only have a single DIM-01 device, so that's the only one I know for sure works.
|
|
||||||
- Only one channel per device is expected to work right now. E.g. only one lamp connected to a DIM-02 will show up in Home Assistant.
|
|
||||||
|
|
||||||
## About connections
|
|
||||||
|
|
||||||
Plejd devices doesn't seem to like to have multiple connections going.
|
|
||||||
Once a controller like the official Plejd app or Home Assistant connects, they will hide their precense from everyone else until a time after that connection is broken.
|
|
||||||
|
|
||||||
That means that if you only have one Plejd device you may not be able to use Home Assistant and the app to controll the device at the same time, and either may have a hard time connecting while the other is running.
|
|
||||||
|
|
||||||
Even after turning off the app or Home Assistant it may take 30 minutes to several hours before the othe rcan connect again. Turning off bluetooth on the last connected device or cutting power to the Plejd for a minute may help.
|
|
||||||
|
|
||||||
|
|
||||||
## Getting more debug information
|
## Getting more debug information
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ async def async_setup_entry(hass, config_entry):
|
|||||||
plejdManager = pyplejd.PlejdManager(config_entry.data)
|
plejdManager = pyplejd.PlejdManager(config_entry.data)
|
||||||
|
|
||||||
devices = await plejdManager.get_devices()
|
devices = await plejdManager.get_devices()
|
||||||
|
scenes = await plejdManager.get_scenes()
|
||||||
|
|
||||||
# Add a service entry if there are no devices - just so the user can get diagnostics data
|
# Add a service entry if there are no devices - just so the user can get diagnostics data
|
||||||
if sum(d.type in ["light", "switch"] for d in devices.values()) == 0:
|
if sum(d.type in ["light", "switch"] for d in devices.values()) == 0:
|
||||||
@ -52,6 +53,9 @@ async def async_setup_entry(hass, config_entry):
|
|||||||
hass.data[DOMAIN].setdefault("devices", {}).update({
|
hass.data[DOMAIN].setdefault("devices", {}).update({
|
||||||
config_entry.entry_id: devices
|
config_entry.entry_id: devices
|
||||||
})
|
})
|
||||||
|
hass.data[DOMAIN].setdefault("scenes", {}).update({
|
||||||
|
config_entry.entry_id: scenes
|
||||||
|
})
|
||||||
hass.data[DOMAIN].setdefault("manager", {}).update({
|
hass.data[DOMAIN].setdefault("manager", {}).update({
|
||||||
config_entry.entry_id: plejdManager,
|
config_entry.entry_id: plejdManager,
|
||||||
})
|
})
|
||||||
@ -83,7 +87,9 @@ async def async_setup_entry(hass, config_entry):
|
|||||||
plejdManager.add_mesh_device(service_info.device)
|
plejdManager.add_mesh_device(service_info.device)
|
||||||
|
|
||||||
|
|
||||||
await hass.config_entries.async_forward_entry_setups(config_entry, ["light", "switch"])
|
await hass.config_entries.async_forward_entry_setups(config_entry,
|
||||||
|
["light", "switch", "button"]
|
||||||
|
)
|
||||||
|
|
||||||
# Ping mesh intermittently to keep the connection alive
|
# Ping mesh intermittently to keep the connection alive
|
||||||
async def _ping(now=None):
|
async def _ping(now=None):
|
||||||
|
47
custom_components/plejd/button.py
Normal file
47
custom_components/plejd/button.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
from homeassistant.components.button import ButtonEntity
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
DOMAIN = "plejd"
|
||||||
|
|
||||||
|
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||||
|
scenes = hass.data[DOMAIN]["scenes"].get(config_entry.entry_id, [])
|
||||||
|
|
||||||
|
entities = []
|
||||||
|
for s in scenes:
|
||||||
|
button = PlejdSceneButton(s, config_entry.entry_id)
|
||||||
|
entities.append(button)
|
||||||
|
async_add_entities(entities, False)
|
||||||
|
|
||||||
|
class PlejdSceneButton(ButtonEntity):
|
||||||
|
|
||||||
|
def __init__(self, device, entry_id):
|
||||||
|
super().__init__()
|
||||||
|
self.device = device
|
||||||
|
self.entry_id = entry_id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_info(self):
|
||||||
|
return {
|
||||||
|
"identifiers": {(DOMAIN, f"{self.entry_id}:{self.device.index}")},
|
||||||
|
"name": self.device.name,
|
||||||
|
"manufacturer": "Plejd",
|
||||||
|
#"connections": ???,
|
||||||
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_entity_name(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def unique_id(self):
|
||||||
|
return f"{self.entry_id}:{self.device.index}"
|
||||||
|
|
||||||
|
async def async_press(self):
|
||||||
|
await self.device.activate()
|
@ -1,4 +1,3 @@
|
|||||||
from builtins import property
|
|
||||||
import logging
|
import logging
|
||||||
from homeassistant.components.light import LightEntity, ColorMode
|
from homeassistant.components.light import LightEntity, ColorMode
|
||||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity, DataUpdateCoordinator
|
from homeassistant.helpers.update_coordinator import CoordinatorEntity, DataUpdateCoordinator
|
||||||
|
@ -4,8 +4,8 @@ from datetime import timedelta
|
|||||||
from bleak_retry_connector import close_stale_connections
|
from bleak_retry_connector import close_stale_connections
|
||||||
|
|
||||||
from .mesh import PlejdMesh
|
from .mesh import PlejdMesh
|
||||||
from .api import get_cryptokey, get_devices, get_site_data
|
from .api import get_cryptokey, get_devices, get_site_data, get_scenes
|
||||||
from .plejd_device import PlejdDevice
|
from .plejd_device import PlejdDevice, PlejdScene
|
||||||
|
|
||||||
from .const import PLEJD_SERVICE
|
from .const import PLEJD_SERVICE
|
||||||
|
|
||||||
@ -18,6 +18,7 @@ class PlejdManager:
|
|||||||
self.mesh = PlejdMesh()
|
self.mesh = PlejdMesh()
|
||||||
self.mesh.statecallback = self._update_device
|
self.mesh.statecallback = self._update_device
|
||||||
self.devices = { }
|
self.devices = { }
|
||||||
|
self.scenes = []
|
||||||
self.credentials = credentials
|
self.credentials = credentials
|
||||||
|
|
||||||
def add_mesh_device(self, device):
|
def add_mesh_device(self, device):
|
||||||
@ -46,6 +47,13 @@ class PlejdManager:
|
|||||||
_LOGGER.info(self.devices)
|
_LOGGER.info(self.devices)
|
||||||
return self.devices
|
return self.devices
|
||||||
|
|
||||||
|
async def get_scenes(self):
|
||||||
|
scenes = await get_scenes(**self.credentials)
|
||||||
|
self.scenes = [PlejdScene(self, **s) for s in scenes]
|
||||||
|
_LOGGER.info("Scenes")
|
||||||
|
_LOGGER.info(self.scenes)
|
||||||
|
return self.scenes
|
||||||
|
|
||||||
async def _update_device(self, deviceState):
|
async def _update_device(self, deviceState):
|
||||||
address = deviceState["address"]
|
address = deviceState["address"]
|
||||||
if address in self.devices:
|
if address in self.devices:
|
||||||
|
@ -103,3 +103,18 @@ async def get_devices(**credentials):
|
|||||||
}
|
}
|
||||||
|
|
||||||
return retval
|
return retval
|
||||||
|
|
||||||
|
async def get_scenes(**credentials):
|
||||||
|
site_data = await get_site_data(**credentials)
|
||||||
|
retval = []
|
||||||
|
for scene in site_data["scenes"]:
|
||||||
|
if scene["hiddenFromSceneList"]: continue
|
||||||
|
sceneId = scene["sceneId"]
|
||||||
|
index = site_data["sceneIndex"].get(sceneId)
|
||||||
|
|
||||||
|
retval.append({
|
||||||
|
"index": index,
|
||||||
|
"title": scene["title"],
|
||||||
|
})
|
||||||
|
|
||||||
|
return retval
|
||||||
|
@ -136,6 +136,13 @@ class PlejdMesh():
|
|||||||
await self.poll()
|
await self.poll()
|
||||||
return retval
|
return retval
|
||||||
|
|
||||||
|
async def activate_scene(self, index):
|
||||||
|
payload = binascii.a2b_hex(f"0201100021{index:02x}")
|
||||||
|
retval = await self.write(payload)
|
||||||
|
if self.pollonWrite:
|
||||||
|
await self.poll()
|
||||||
|
return retval
|
||||||
|
|
||||||
async def ping(self):
|
async def ping(self):
|
||||||
if self.client is None:
|
if self.client is None:
|
||||||
return False
|
return False
|
||||||
|
@ -48,7 +48,6 @@ class PlejdDevice:
|
|||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<PlejdDevice(<manager>, {self.address}, {self.BLE_address}, {self.data}>"
|
return f"<PlejdDevice(<manager>, {self.address}, {self.BLE_address}, {self.data}>"
|
||||||
pass
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def available(self):
|
def available(self):
|
||||||
@ -111,3 +110,24 @@ class PlejdDevice:
|
|||||||
|
|
||||||
async def turn_off(self):
|
async def turn_off(self):
|
||||||
await self.manager.mesh.set_state(self.address, False)
|
await self.manager.mesh.set_state(self.address, False)
|
||||||
|
|
||||||
|
class PlejdScene:
|
||||||
|
|
||||||
|
def __init__(self, manager, index, title):
|
||||||
|
self._manager = manager
|
||||||
|
self._index = index
|
||||||
|
self._title = title
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"<PlejdScene(<manager>, {self._index}, '{self._title}'>"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return self._title
|
||||||
|
|
||||||
|
@property
|
||||||
|
def index(self):
|
||||||
|
return self._index
|
||||||
|
|
||||||
|
async def activate(self):
|
||||||
|
await self._manager.mesh.activate_scene(self._index)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user