Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add redgtech integration #136947

Open
wants to merge 15 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .strict-typing
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,7 @@ homeassistant.components.raspberry_pi.*
homeassistant.components.rdw.*
homeassistant.components.recollect_waste.*
homeassistant.components.recorder.*
homeassistant.components.redgtech.*
homeassistant.components.remote.*
homeassistant.components.renault.*
homeassistant.components.reolink.*
Expand Down
69 changes: 69 additions & 0 deletions homeassistant/components/redgtech/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import logging
from homeassistant.core import HomeAssistant
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from .const import DOMAIN, API_URL
from homeassistant.helpers.aiohttp_client import async_get_clientsession
import aiohttp
from redgtech_api import RedgtechAPI

_LOGGER = logging.getLogger(__name__)

PLATFORMS: list[Platform] = [Platform.SWITCH]

async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Redgtech from a config entry."""
_LOGGER.debug("Setting up Redgtech entry: %s", entry.entry_id)
hass.data.setdefault(DOMAIN, {})
hass.data[DOMAIN][entry.entry_id] = {
"config": entry.data,
"entities": []
}

access_token = entry.data.get("access_token")
if not access_token:
_LOGGER.error("No access token found in config entry")
return False

session = async_get_clientsession(hass)
try:
async with session.get(f'{API_URL}/home_assistant?access_token={access_token}', timeout=10) as response:
response.raise_for_status()
data = await response.json()
_LOGGER.debug("Received data from API: %s", data)

entities = []
for item in data.get("boards", []):
entity_id = item.get('endpointId', '')
entity_name = item.get("name", f"Entity {entity_id}")
entity_value = item.get("value", False)
entity_state = "on" if entity_value else "off"
_LOGGER.debug("Processing entity: id=%s, name=%s, value=%s, state=%s", entity_id, entity_name, entity_value, entity_state)

entities.append({
"id": entity_id,
"name": entity_name,
"state": entity_state,
"type": 'switch'
})

hass.data[DOMAIN][entry.entry_id]["entities"] = entities

await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
_LOGGER.debug("Successfully set up Redgtech entry: %s", entry.entry_id)
return True

except aiohttp.ClientResponseError as e:
_LOGGER.error("HTTP error while setting up Redgtech entry: %s - Status: %s", e.message, e.status)
return False
except aiohttp.ClientError as e:
_LOGGER.error("Client error while setting up Redgtech entry: %s", e)
return False
except Exception as e:
_LOGGER.exception("Unexpected error setting up Redgtech entry: %s", entry.entry_id)
return False

async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
_LOGGER.debug("Unloading Redgtech entry: %s", entry.entry_id)
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
55 changes: 55 additions & 0 deletions homeassistant/components/redgtech/config_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from homeassistant import config_entries
import voluptuous as vol
import aiohttp
import logging
from .const import DOMAIN, API_URL

_LOGGER = logging.getLogger(__name__)

class RedgtechConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Config Flow for Redgtech integration."""

VERSION = 1

async def async_step_user(self, user_input=None):
"""Handle the initial user step for login."""
errors = {}

if user_input is not None:
email = user_input.get("email")
password = user_input.get("password")

try:
async with aiohttp.ClientSession() as session:
async with session.post(
f'{API_URL}/home_assistant/login',
json={'email': email, 'password': password}
) as response:
if response.status == 200:
data = await response.json()
access_token = data.get("data", {}).get("access_token")
if access_token:
_LOGGER.info("Login successful")

return self.async_create_entry(
title="Redgtech",
data={"access_token": access_token}
)
else:
_LOGGER.error("Login failed: No access token received")
errors["base"] = "invalid_auth"
else:
_LOGGER.error("Login failed: Invalid credentials")
errors["base"] = "invalid_auth"
except aiohttp.ClientError as e:
_LOGGER.error("Login failed: Cannot connect to server: %s", e)
errors["base"] = "cannot_connect"

return self.async_show_form(
step_id="user",
data_schema=vol.Schema({
vol.Required("email"): str,
vol.Required("password"): str,
}),
errors=errors
)
2 changes: 2 additions & 0 deletions homeassistant/components/redgtech/const.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
DOMAIN = "redgtech"
API_URL = "https://redgtech-dev.com"
12 changes: 12 additions & 0 deletions homeassistant/components/redgtech/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"domain": "redgtech",
"name": "Redgtech",
"codeowners": [],
"documentation": "https://www.home-assistant.io/integrations/redgtech",
"iot_class": "cloud_polling",
"logo": "/brands/redgtech/logo.png",
"integration_type": "service",
"config_flow": true,
"quality_scale": "silver",
"requirements": ["redgtech-api==0.1.2"]
}
90 changes: 90 additions & 0 deletions homeassistant/components/redgtech/quality_scale.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
rules:
# Bronze
action-setup:
status: exempt
comment: only entity actions
appropriate-polling:
status: exempt
comment: the integration does not poll
brands: done
common-modules:
status: exempt
comment: the integration currently implements only one platform and has no coordinator
config-flow-test-coverage: done
config-flow: done
dependency-transparency: done
docs-actions: done
docs-high-level-description: done
docs-installation-instructions: done
docs-removal-instructions: done
entity-event-setup:
status: exempt
comment: the integration does not subscribe to events
entity-unique-id: done
has-entity-name: done
runtime-data: done
test-before-configure:
status: done
comment: tested by publishing a success message to the topic
test-before-setup:
status: exempt
comment: testing would require to trigger a notification
unique-config-entry: done

# Silver
action-exceptions: done
config-entry-unloading: done
docs-configuration-parameters:
status: exempt
comment: the integration has no options
docs-installation-parameters: done
entity-unavailable:
status: exempt
comment: the integration only implements a stateless notify entity.
integration-owner: done
log-when-unavailable:
status: exempt
comment: the integration only integrates state-less entities
parallel-updates: done
reauthentication-flow:
status: exempt
comment: the integration currently does not implement authenticated requests
test-coverage: done

# Gold
devices: todo
diagnostics: todo
discovery-update-info: todo
discovery: todo
docs-data-update: todo
docs-examples: todo
docs-known-limitations: todo
docs-supported-devices: todo
docs-supported-functions: todo
docs-troubleshooting: todo
docs-use-cases: todo
dynamic-devices: todo
entity-category: done
entity-device-class:
status: exempt
comment: no suitable device class for the notify entity
entity-disabled-by-default:
status: exempt
comment: only one entity
entity-translations:
status: exempt
comment: the notify entity uses the topic as name, no translation required
exception-translations: done
icon-translations: done
reconfiguration-flow: todo
repair-issues:
status: exempt
comment: the integration has no repeairs
stale-devices:
status: exempt
comment: only one device per entry, is deleted with the entry.

# Platinum
async-dependency: done
inject-websession: done
strict-typing: done
12 changes: 12 additions & 0 deletions homeassistant/components/redgtech/services.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
login:
description: "Log in to the Redgtech service"
fields:
email:
description: "The email address for the Redgtech account"
example: "[email protected]"
password:
description: "The password for the Redgtech account"
example: "your_password"

logout:
description: "Log out from the Redgtech service"
67 changes: 67 additions & 0 deletions homeassistant/components/redgtech/strings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
{
"config": {
"step": {
"user": {
"title": "User Configuration",
"description": "Please enter your email address.",
"data": {
"email": "Email",
"password": "Password"
}
}
}
},
"common": {
"generic": {
"model": "Model",
"ui_managed": "Managed via UI"
},
"device_automation": {
"condition_type": {
"is_on": "{entity_name} is on",
"is_off": "{entity_name} is off"
},
"extra_fields": {
"above": "Above",
"below": "Below",
"for": "Duration",
"to": "To",
"value": "Value",
"zone": "Zone"
},
"trigger_type": {
"changed_states": "{entity_name} turned on or off",
"turned_on": "{entity_name} turned on",
"turned_off": "{entity_name} turned off"
},
"action_type": {
"toggle": "Toggle {entity_name}",
"turn_on": "Turn on {entity_name}",
"turn_off": "Turn off {entity_name}"
}
},
"action": {
"connect": "Connect",
"disconnect": "Disconnect",
"enable": "Enable",
"disable": "Disable",
"open": "Open",
"close": "Close",
"reload": "Reload",
"restart": "Restart",
"start": "Start",
"stop": "Stop",
"pause": "Pause",
"turn_on": "Turn on",
"turn_off": "Turn off",
"toggle": "Toggle"
},
"time": {
"sunday": "Sunday"
},
"state": {
"not_home": "Away"
},
"config_flow": {}
}
}
Loading