Skip to content

Commit

Permalink
Merge pull request #7 from hsk-dk/hsk-dk-local-sync-1
Browse files Browse the repository at this point in the history
Update __init__.py
  • Loading branch information
hsk-dk authored Feb 16, 2025
2 parents 5787cd5 + 49c5fe8 commit d3fc2b4
Show file tree
Hide file tree
Showing 7 changed files with 257 additions and 79 deletions.
75 changes: 37 additions & 38 deletions thermex_api/api.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
"""Thermex API module"""
import aiohttp
import json
import logging
Expand All @@ -16,6 +15,22 @@ def __init__(self, host, code):
self._password = code
self._coordinator = None

@property
def coordinator(self):
"""Return the coordinator."""
return self._coordinator

async def async_setup_coordinator(self):
"""Set up data update coordinator."""
self._coordinator = DataUpdateCoordinator(
self._host,
_LOGGER,
name="thermex_data",
update_method=self.async_get_data,
update_interval=timedelta(seconds=10),
)
await self._coordinator.async_refresh()

async def authenticate(self, websocket):
auth_message = {
"Request": "Authenticate",
Expand All @@ -31,6 +46,26 @@ async def authenticate(self, websocket):
else:
_LOGGER.error("Authentication failed")
return False

async def fetch_status(self):
"""Fetch status of fan and light."""
async with aiohttp.ClientSession() as session:
async with session.ws_connect(f'ws://{self._host}:9999/api') as websocket:
await self.authenticate(websocket)
_LOGGER.debug("Fetching fan and light status")
await websocket.send_json({"Request": "STATUS"})
response = await websocket.receive()
response = json.loads(response.data)
_LOGGER.debug("Status response: %s", response)
if response.get("Response") == "Status":
return response.get("Data")
else:
_LOGGER.error("Error fetching status: %s", response)
raise Exception("Unexpected response from Thermex API")

async def async_get_data(self):
"""Fetch and return status data."""
return await self.fetch_status()

async def get_fan_status(self):
"""Get the status of the fan."""
Expand All @@ -49,7 +84,7 @@ async def get_fan_status(self):
raise Exception("api.py Uventet svar fra Thermex API")
else:
_LOGGER.error("api.py Fejl under hentning af fan status")

async def update_fan(self, fanonoff, fanspeed):
"""Update fan settings."""
async with aiohttp.ClientSession() as session:
Expand All @@ -71,42 +106,6 @@ async def update_fan(self, fanonoff, fanspeed):
else:
_LOGGER.error("Update failed due to authentication failure")

async def fetch_status(self):
"""Fetch status of fan and light."""
async with aiohttp.ClientSession() as session:
async with session.ws_connect(f'ws://{self._host}:9999/api') as websocket:
await self.authenticate(websocket)
_LOGGER.debug("Fetching fan and light status")
await websocket.send_json({"Request": "STATUS"})
response = await websocket.receive()
response = json.loads(response.data)
_LOGGER.debug("Status response: %s", response)
if response.get("Response") == "Status":
return response.get("Data")
else:
_LOGGER.error("Error fetching status: %s", response)
raise Exception("Unexpected response from Thermex API")

async def async_get_data(self):
"""Fetch and return status data."""
return await self.fetch_status()

async def async_setup_coordinator(self):
"""Set up data update coordinator."""
self._coordinator = DataUpdateCoordinator(
self._host,
_LOGGER,
name="thermex_data",
update_method=self.async_get_data,
update_interval=timedelta(seconds=10),
)
await self._coordinator.async_refresh()

@property
def coordinator(self):
"""Return the coordinator."""
return self._coordinator

async def update_light(self, lightonoff, brightness=None):
"""Update light settings."""
_LOGGER.debug("update_light(%s)", lightonoff)
Expand Down
49 changes: 49 additions & 0 deletions thermex_api/config_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""Config flow for Thermex_fan integration."""
import logging
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.loader import Integration
from .const import DOMAIN

_LOGGER = logging.getLogger(__name__)

DATA_SCHEMA = vol.Schema(
{
vol.Required("host", description={"suggested_value": "example.com"}): str,
vol.Required("password", description={"suggested_value": ""}): str,
}
)

class ThermexConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
async def async_step_user(self, user_input=None):
errors = {}

if user_input is not None:
host = user_input['host']
password = user_input['password']

# Your authentication logic goes here

# If authentication is successful
unique_id = f"thermex_{host}"
name = "Thermex"

await self.async_set_unique_id(unique_id)
self._abort_if_unique_id_configured()

self.context["title_placeholders"] = {"unique_id": unique_id}

# Create entry with device name and data
return self.async_create_entry(title=name, data=user_input)

return self.async_show_form(
step_id="user",
data_schema=DATA_SCHEMA,
errors=errors,
description_placeholders={
"title": await self.hass.components.frontend.async_get_translations(self.hass, "config_flow", "title"),
"description": await self.hass.components.frontend.async_get_translations(self.hass, "config_flow", "description"),
"host_label": await self.hass.components.frontend.async_get_translations(self.hass, "config_flow", "host_label"),
"password_label": await self.hass.components.frontend.async_get_translations(self.hass, "config_flow", "password_label"),
}
)
90 changes: 57 additions & 33 deletions thermex_api/light.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import logging
#from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity import Entity
from homeassistant.components.light import ColorMode, LightEntity, LightEntityFeature

from .const import DOMAIN
Expand All @@ -18,13 +18,59 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=

class ThermexLight(LightEntity):
"""Representation of a light entity."""
_attr_color_mode = ColorMode.BRIGHTNESS
_attr_supported_color_modes = {ColorMode.BRIGHTNESS}

def __init__(self, coordinator, name="Thermex Light"):
"""Initialize the light entity."""
self._coordinator = coordinator
self._name = name
self._attr_name = name
self._state = None
self._brightness = None
self._attr_brightness = None
self._attr_unique_id = "fsfdsfsdfsdf3r"

@property
def unique_id(self):
"""Return the name of the light."""
return self._attr_unique_id

@property
def name(self):
"""Return the name of the light."""
return self._attr_name

@property
def supported_color_modes(self):
"""Set of supported color modes."""
return self._attr_supported_color_modes

@property
def color_mode(self):
"""Current color mode of the light."""
if self._attr_state == True:
if self._attr_brightness is not None:
self._attr_color_mode = ColorMode.BRIGHTNESS
self._attr_color_mode = ColorMode.ONOFF
self._attr_color_mode = ColorMode.UNKNOWN
return self._attr_color_mode

@property
def is_on(self):
"""Return true if the light is on."""
return self._attr_state

@property
def brightness(self):
"""Return the brightness of the light."""
return self._attr_brightness

@property
def icon(self) -> str | None:
"""Icon based on state."""
if self._attr_state:
return "mdi:pot-steam"
else:
return "mdi:pot-steam-outline"

async def async_update(self):
"""Fetch the latest data from the coordinator."""
Expand All @@ -36,37 +82,20 @@ async def async_update(self):
_LOGGER.debug("Light on/off status: %s", lightonoff)

if lightonoff == 1:
self._state = True
self._attr_state = True
elif lightonoff == 0:
self._state = False
self._attr_state = False
else:
_LOGGER.warning("Unexpected value for lightonoff: %s", lightonoff)
self._state = None
self._attr_state = None

_LOGGER.debug("Light status sat: %s", self._state)
self._brightness = light_data.get("lightbrightness")

@property
def supported_color_modes(self):
"""Set of supported color modes."""
return {ColorMode.ONOFF, ColorMode.BRIGHTNESS}

@property
def color_mode(self):
"""Current color mode of the light."""
if self._brightness is not None:
return ColorMode.BRIGHTNESS
return ColorMode.ONOFF

@property
def name(self):
"""Return the name of the light."""
return self._name

@property
def is_on(self):
"""Return true if the light is on."""
return self._state
if self._attr_state == True:
if self._attr_brightness is not None:
self._attr_color_mode = ColorMode.BRIGHTNESS
self._attr_color_mode = ColorMode.ONOFF
self._attr_color_mode = ColorMode.UNKNOWN

async def async_turn_on(self, **kwargs):
"""Turn on the light."""
Expand All @@ -76,8 +105,3 @@ async def async_turn_on(self, **kwargs):
async def async_turn_off(self, **kwargs):
"""Turn off the light."""
await self._coordinator.update_light(lightonoff=0)

@property
def brightness(self):
"""Return the brightness of the light."""
return self._brightness
2 changes: 1 addition & 1 deletion thermex_api/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
"codeowners": ["@hsk-dk"],
"config_flow": false,
"requirements": [],
"version": "0.0.1",
"version": "0.0.2",
"iot_class": "local_pool"
}
35 changes: 28 additions & 7 deletions thermex_api/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ class ThermexFanSensor(Entity):

def __init__(self, coordinator):
"""Initialize the sensor."""
#self._api = api
self._state = None
self._coordinator = coordinator
self._speeds = {
Expand All @@ -29,14 +28,15 @@ def __init__(self, coordinator):
3: "høj",
4: "boost"
}
self._attr_unique_id = "fdddsfdsfsdfsdf3r"

_LOGGER.debug("Sensor.py Thermex ThermexFanSensor initialiseret")

async def async_update(self):
"""Fetch the latest data from the coordinator."""
data = await self._coordinator.async_get_data()
fan_data = data.get("Fan", {})
self._state = self._speeds.get(fan_data.get("fanspeed", 0), "ukendt")

@property
def unique_id(self):
"""Return the name of the light."""
return self._attr_unique_id

@property
def name(self):
"""Return the name of the sensor."""
Expand All @@ -51,3 +51,24 @@ def state(self):
def unit_of_measurement(self):
"""Return the unit of measurement."""
return None

@property
def icon(self) -> str | None:
"""Icon based on state."""
if self._attr_state == "Lav":
return "mdi:fan-speed-1"
elif self._attr_state == "Mellem":
return "mdi:fan-speed-2"
elif self._attr_state == "Høj":
return "mdi:fan-speed-3"
elif self._attr_state == "Boost":
return "mdi:fan-plus"
else:
return "mdi:fan-off"

async def async_update(self):
"""Fetch the latest data from the coordinator."""
data = await self._coordinator.async_get_data()
fan_data = data.get("Fan", {})
self._state = self._speeds.get(fan_data.get("fanspeed", 0), "ukendt")

Loading

0 comments on commit d3fc2b4

Please sign in to comment.