forked from platypush/platypush
[light.hue] Better bridge errors management.
This commit is contained in:
parent
58ab04bbbd
commit
24449c9995
1 changed files with 51 additions and 15 deletions
|
@ -40,8 +40,7 @@ class LightHuePlugin(RunnablePlugin, LightEntityManager):
|
||||||
MIN_CT = 154
|
MIN_CT = 154
|
||||||
MAX_CT = 500
|
MAX_CT = 500
|
||||||
ANIMATION_CTRL_QUEUE_NAME = 'platypush/light/hue/AnimationCtrl'
|
ANIMATION_CTRL_QUEUE_NAME = 'platypush/light/hue/AnimationCtrl'
|
||||||
_BRIDGE_RECONNECT_SECONDS = 5
|
_MAX_RECONNECT_SECS = 60
|
||||||
_MAX_RECONNECT_TRIES = 5
|
|
||||||
_UNINITIALIZED_BRIDGE_ERR = 'The Hue bridge is not initialized'
|
_UNINITIALIZED_BRIDGE_ERR = 'The Hue bridge is not initialized'
|
||||||
|
|
||||||
class Animation(Enum):
|
class Animation(Enum):
|
||||||
|
@ -67,7 +66,7 @@ class LightHuePlugin(RunnablePlugin, LightEntityManager):
|
||||||
bridge: str,
|
bridge: str,
|
||||||
lights: Optional[Iterable[str]] = None,
|
lights: Optional[Iterable[str]] = None,
|
||||||
groups: Optional[Iterable[str]] = None,
|
groups: Optional[Iterable[str]] = None,
|
||||||
poll_interval: float = 20.0,
|
poll_interval: Optional[float] = 20.0,
|
||||||
config_file: Optional[str] = None,
|
config_file: Optional[str] = None,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
):
|
):
|
||||||
|
@ -161,6 +160,23 @@ class LightHuePlugin(RunnablePlugin, LightEntityManager):
|
||||||
for light_id in self._get_lights():
|
for light_id in self._get_lights():
|
||||||
self.animations['lights'][light_id] = None
|
self.animations['lights'][light_id] = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _parse_error(cls, response) -> Optional[str]:
|
||||||
|
errors = []
|
||||||
|
if isinstance(response, (list, tuple, set)):
|
||||||
|
errors = [e for e in [cls._parse_error(r) for r in response] if e]
|
||||||
|
elif isinstance(response, dict):
|
||||||
|
error = response.get('error')
|
||||||
|
if not error:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if isinstance(error, dict):
|
||||||
|
error = error.get('description', error.get('type', 'Unknown error'))
|
||||||
|
|
||||||
|
errors = [error]
|
||||||
|
|
||||||
|
return ', '.join(errors)
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def connect(self):
|
def connect(self):
|
||||||
"""
|
"""
|
||||||
|
@ -173,29 +189,49 @@ class LightHuePlugin(RunnablePlugin, LightEntityManager):
|
||||||
if not self.bridge:
|
if not self.bridge:
|
||||||
from phue import Bridge, PhueRegistrationException
|
from phue import Bridge, PhueRegistrationException
|
||||||
|
|
||||||
success = False
|
|
||||||
n_tries = 0
|
n_tries = 0
|
||||||
|
retry_secs = 2
|
||||||
|
|
||||||
while not success:
|
while True:
|
||||||
try:
|
try:
|
||||||
n_tries += 1
|
n_tries += 1
|
||||||
self.bridge = Bridge(
|
self.bridge = Bridge(
|
||||||
self.bridge_address, config_file_path=self.config_file
|
self.bridge_address, config_file_path=self.config_file
|
||||||
)
|
)
|
||||||
|
|
||||||
success = True
|
self.bridge.connect()
|
||||||
except PhueRegistrationException as e:
|
# Check the connection (newer versions of the API may not
|
||||||
self.logger.warning('Bridge registration error: %s', e)
|
# throw an exception if the bridge is not paired)
|
||||||
|
err = self._parse_error(self.bridge.get_api())
|
||||||
|
if err in {
|
||||||
|
'method, GET, not available for resource, /',
|
||||||
|
'unauthorized user',
|
||||||
|
}:
|
||||||
|
raise PhueRegistrationException(id=1, message=err)
|
||||||
|
|
||||||
if n_tries >= self._MAX_RECONNECT_TRIES:
|
assert not err, err
|
||||||
self.logger.error(
|
break
|
||||||
(
|
except Exception as e:
|
||||||
'Bridge registration failed after ' + '{} attempts'
|
retry_secs = min(retry_secs * 2, self._MAX_RECONNECT_SECS)
|
||||||
).format(n_tries)
|
if isinstance(e, PhueRegistrationException):
|
||||||
|
self.logger.warning('Bridge registration error: %s', e.message) # type: ignore
|
||||||
|
err = 'Press the pairing button on the bridge'
|
||||||
|
if os.path.exists(self.config_file):
|
||||||
|
err += f', or remove the config file {self.config_file}'
|
||||||
|
|
||||||
|
legacy_config_file = os.path.join(
|
||||||
|
os.path.expanduser('~'), '.python_hue'
|
||||||
)
|
)
|
||||||
break
|
|
||||||
|
|
||||||
time.sleep(self._BRIDGE_RECONNECT_SECONDS)
|
if os.path.exists(legacy_config_file):
|
||||||
|
err += f' (or {legacy_config_file})'
|
||||||
|
|
||||||
|
self.logger.info(err)
|
||||||
|
else:
|
||||||
|
self.logger.error('Error connecting to the bridge: %s', e)
|
||||||
|
|
||||||
|
self.logger.info('Retrying in %d seconds', retry_secs)
|
||||||
|
time.sleep(retry_secs)
|
||||||
|
|
||||||
self.logger.info('Bridge connected')
|
self.logger.info('Bridge connected')
|
||||||
self.get_scenes()
|
self.get_scenes()
|
||||||
|
|
Loading…
Reference in a new issue