Skip to content

Commit

Permalink
Merge pull request #93 from jeremyheslop/master
Browse files Browse the repository at this point in the history
Updates to code to fix wifi bulbs
  • Loading branch information
jfarmer08 authored Jan 6, 2025
2 parents 84111f6 + ec6bd12 commit cbb0000
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 131 deletions.
102 changes: 39 additions & 63 deletions custom_components/sengledapi/light.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/python3

"""Platform for light Sengled hintegration."""
"""Platform for light Sengled integration."""

import logging
from datetime import timedelta
Expand All @@ -11,11 +11,8 @@
ATTR_COLOR_TEMP,
ATTR_HS_COLOR,
PLATFORM_SCHEMA,
SUPPORT_BRIGHTNESS,
SUPPORT_COLOR_TEMP,
SUPPORT_COLOR,
LightEntity,
ColorMode,
LightEntity,
)
from homeassistant.const import ATTR_ATTRIBUTION
from homeassistant.util import color as colorutil
Expand All @@ -33,7 +30,7 @@

async def async_setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Sengled Light platform."""
_LOGGER.debug("""Creating new Sengled light component""")
_LOGGER.debug("Creating new Sengled light component")
# Add devices
add_entities(
[
Expand All @@ -55,7 +52,7 @@ def __init__(self, light):
self._name = light._friendly_name
self._state = light._state
self._brightness = light._brightness
self._avaliable = light._avaliable
self._available = light._available
self._device_mac = light._device_mac
self._device_model = light._device_model
self._color_temperature = light._color_temperature
Expand Down Expand Up @@ -83,42 +80,28 @@ def unique_id(self):

@property
def available(self):
"""Return the connection status of this light"""
_LOGGER.debug("Light.py _avaliable %s", self._avaliable)
return self._avaliable
"""Return the connection status of this light."""
_LOGGER.debug("Light.py _available %s", self._available)
return self._available

@property
def extra_state_attributes(self):
"""Return device attributes of the entity."""
if self._device_model == "E13-N11":
return {
ATTR_ATTRIBUTION: ATTRIBUTION,
"state": self._state,
"available": self._avaliable,
"device model": self._device_model,
"rssi": self._device_rssi,
"mac": self._device_mac,
"alarm status ": self._alarm_status,
"color": self._color,
"color Temp": self._color_temperature,
"color r": self._rgb_color_r,
"color g": self._rgb_color_g,
"color b": self._rgb_color_b,
}
else:
return {
ATTR_ATTRIBUTION: ATTRIBUTION,
"state": self._state,
"available": self._avaliable,
"device model": self._device_model,
"rssi": self._device_rssi,
"mac": self._device_mac,
"color": self._color,
"color Temp": self._color_temperature,
"color r": self._rgb_color_r,
"color g": self._rgb_color_g,
"color b": self._rgb_color_b,
}
attributes = {
ATTR_ATTRIBUTION: ATTRIBUTION,
"state": self._state,
"available": self._available,
"device model": self._device_model,
"rssi": self._device_rssi,
"mac": self._device_mac,
"alarm status ": self._alarm_status,
"color": self._color,
"color Temp": self._color_temperature,
"color r": self._rgb_color_r,
"color g": self._rgb_color_g,
"color b": self._rgb_color_b,
}
return attributes

@property
def color_temp(self):
Expand Down Expand Up @@ -154,38 +137,31 @@ def is_on(self):
return self._state

@property
def supported_features(self):
"""Flags Supported Features"""
features = 0
def supported_color_modes(self):
"""Return the supported color modes for the light."""
color_modes = set()
if self._support_brightness:
features = SUPPORT_BRIGHTNESS
color_modes.add(ColorMode.BRIGHTNESS)
if self._support_color_temp:
features = features | SUPPORT_COLOR_TEMP
color_modes.add(ColorMode.COLOR_TEMP)
if self._support_color:
features = features | SUPPORT_COLOR
_LOGGER.debug("supported_features: %s", features)
return features
color_modes.add(ColorMode.HS)
return color_modes

@property
def supported_color_modes(self):
"""Flags Supported Features"""
features = set()
if self._support_brightness:
features.add(ColorMode.BRIGHTNESS)
if self._support_color_temp:
features.add(ColorMode.COLOR_TEMP)
def color_mode(self):
"""Return the current color mode of the light."""
if self._support_color:
features.add(ColorMode.HS)
_LOGGER.debug("supported_color_modes: %s", features)
return features
return ColorMode.HS
elif self._support_color_temp:
return ColorMode.COLOR_TEMP
else:
return ColorMode.BRIGHTNESS

async def async_turn_on(self, **kwargs):
_LOGGER.debug("turn_on kwargs: %s", kwargs)
"""Turn on or control the light."""
if (
ATTR_BRIGHTNESS not in kwargs
and ATTR_HS_COLOR not in kwargs
and ATTR_COLOR_TEMP not in kwargs
if not any(
key in kwargs for key in (ATTR_BRIGHTNESS, ATTR_HS_COLOR, ATTR_COLOR_TEMP)
):
await self._light.async_toggle(ON)
if ATTR_BRIGHTNESS in kwargs:
Expand All @@ -210,7 +186,7 @@ async def async_update(self):
"""
await self._light.async_update()
self._state = self._light.is_on()
self._avaliable = self._light._avaliable
self._available = self._light._available
self._state = self._light._state
self._brightness = self._light._brightness
self._color_temperature = self._light._color_temperature
Expand Down
6 changes: 2 additions & 4 deletions custom_components/sengledapi/sengledapi/devices/bulbs/bulb.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def __init__(
self._device_mac = device_mac
self._friendly_name = friendly_name
self._state = state
self._avaliable = isonline
self._available = isonline
self._just_changed_state = True
self._device_model = device_model
self._device_rssi = -30
Expand All @@ -67,8 +67,6 @@ async def async_toggle(self, onoff):
if onoff == "1":
self._state = True
else:
# We don't know what is coming in this parameter and the API is sensitive to other values
onoff = "0"
self._state = False
if self._wifi_device:
_LOGGER.info(
Expand All @@ -89,7 +87,7 @@ async def async_toggle(self, onoff):
)
else:
_LOGGER.info(
"SengledApi: Bulb %s %s toggling.",
"SengledApi: Bulb %s %s turning on.",
self._friendly_name,
self._device_mac,
)
Expand Down
8 changes: 6 additions & 2 deletions custom_components/sengledapi/sengledapi/devices/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,9 @@ class AccessTokenError(SengledApiError):
pass


class SengledApiAccessToken:
pass
class SengledApiAccessToken(SengledApiError):
"""Raised when the api encounters issues with the AccessToken."""

def __init__(self, message="Invalid or missing AccessToken"):
self.message = message
super().__init__(self.message)
72 changes: 42 additions & 30 deletions custom_components/sengledapi/sengledapi/devices/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,17 @@

_LOGGER.info("SengledApi: Initializing Request")

import asyncio
import functools
from concurrent.futures import ThreadPoolExecutor

async def async_create_ssl_context():
loop = asyncio.get_running_loop()
with ThreadPoolExecutor() as executor:
return await loop.run_in_executor(
executor, functools.partial(ssl.create_default_context, cafile=certifi.where())
)


class Request:
def __init__(self, url, payload, no_return=False):
Expand All @@ -30,33 +41,26 @@ def __init__(self, url, payload, no_return=False):
"Connection": "keep-alive",
}

def get_response(self, jsession_id):
self._header = {
"Content-Type": "application/json",
"Cookie": "JSESSIONID={}".format(jsession_id),
"Connection": "keep-alive",
}

r = requests.post(self._url, headers=self._header, data=self._payload)
data = r.json()
return data

async def async_get_response(self, jsession_id):
self._header = {
"Content-Type": "application/json",
"Cookie": "JSESSIONID={}".format(jsession_id),
"Host": "element.cloud.sengled.com:443",
"Cookie": f"JSESSIONID={jsession_id}",
"Connection": "keep-alive",
}

# Asynchronously create the SSL context in a non-blocking way.
sslcontext = await async_create_ssl_context()

# Use aiohttp's ClientSession for asynchronous HTTP requests.
async with aiohttp.ClientSession() as session:
sslcontext = ssl.create_default_context(cafile=certifi.where())
async with session.post(
self._url, headers=self._header, data=self._payload, ssl=sslcontext
) as resp:
data = await resp.json()
# _LOGGER.debug("SengledApi: data from Response %s ", str(data))
return data
async with session.post(self._url, headers=self._header, data=self._payload, ssl=sslcontext) as response:
# Make sure to handle potential exceptions and non-JSON responses appropriately.
if response.status == 200:
data = await response.json()
return data
else:
_LOGGER.error("Failed to get response, status: %s", response.status)
return None

########################Login#####################################
def get_login_response(self):
Expand All @@ -68,14 +72,18 @@ def get_login_response(self):

async def async_get_login_response(self):
_LOGGER.info("SengledApi: Get Login Response async.")
sslcontext = await async_create_ssl_context()
async with aiohttp.ClientSession() as session:
sslcontext = ssl.create_default_context(cafile=certifi.where())
async with session.post(
self._url, headers=self._header, data=self._payload, ssl=sslcontext
) as resp:
data = await resp.json()
_LOGGER.debug("SengledApi: Get Login Response %s ", str(data))
return data
if resp.status == 200:
data = await resp.json()
_LOGGER.debug("SengledApi: Get Login Response %s ", str(data))
return data
else:
_LOGGER.error("Failed to get login response, status: %s", resp.status)
return None

######################Session Timeout#################################
def is_session_timeout_response(self, jsession_id):
Expand All @@ -100,13 +108,17 @@ async def async_is_session_timeout_response(self, jsession_id):
"sid": jsession_id,
"X-Requested-With": "com.sengled.life2",
}
sslcontext = await async_create_ssl_context()
async with aiohttp.ClientSession() as session:
sslcontext = ssl.create_default_context(cafile=certifi.where())
async with session.post(
self._url, headers=self._header, data=self._payload, ssl=sslcontext
) as resp:
data = await resp.json()
_LOGGER.info(
"SengledApi: Get Session Timeout Response Async %s", str(data)
)
return data
if resp.status == 200:
data = await resp.json()
_LOGGER.info(
"SengledApi: Get Session Timeout Response Async %s", str(data)
)
return data
else:
_LOGGER.error("Failed to get session timeout response, status: %s", resp.status)
return None
Loading

0 comments on commit cbb0000

Please sign in to comment.