Skip to content

Commit bbd29fe

Browse files
committed
Remote 3 Updates
1 parent d3fc09d commit bbd29fe

11 files changed

Lines changed: 57 additions & 50 deletions

File tree

.devcontainer/devcontainer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// See https://aka.ms/vscode-remote/devcontainer.json for format details.
22
{
33
"name": "Home Assistant integration development",
4-
"image": "mcr.microsoft.com/devcontainers/python:dev-3.13",
5-
"postCreateCommand": "sudo apt-get update && sudo apt-get install libturbojpeg0",
4+
"image": "mcr.microsoft.com/devcontainers/python:3.13-bookworm",
5+
"postCreateCommand": ".devcontainer/setup",
66
"postAttachCommand": ".devcontainer/setup",
77
"forwardPorts": [8123],
88
"runArgs": ["-e", "GIT_EDITOR=code --wait", "--network=host"],

.devcontainer/setup

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
#!/usr/bin/env bash
22

3+
sudo apt-get update && sudo apt-get install libturbojpeg0
4+
35
set -e
46

57
cd "$(dirname "$0")/.."
68

7-
python3 -m pip install --requirement requirements.txt
9+
python3 -m pip install --requirement requirements.txt --upgrade
10+
11+
pre-commit install
812

913
mkdir -p config

.pre-commit-config.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
repos:
2+
- repo: https://github.com/astral-sh/ruff-pre-commit
3+
# Ruff version.
4+
rev: v0.9.10
5+
hooks:
6+
# Run the linter.
7+
- id: ruff
8+
args: [--fix]
9+
# Run the formatter.
10+
- id: ruff-format

custom_components/unfoldedcircle/config_flow.py

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
import asyncio
44
import logging
55
from typing import Any, Awaitable, Callable, Type
6+
67
from aiohttp import ClientConnectionError
7-
from pyUnfoldedCircleRemote.const import AUTH_APIKEY_NAME, SIMULATOR_MAC_ADDRESS
8+
from pyUnfoldedCircleRemote.const import AUTH_APIKEY_NAME
89
from pyUnfoldedCircleRemote.remote import (
910
ApiKeyCreateError,
1011
ApiKeyRevokeError,
@@ -19,13 +20,13 @@
1920
from voluptuous import Optional, Required
2021

2122
from homeassistant import config_entries
22-
from homeassistant.helpers.service_info.zeroconf import ZeroconfServiceInfo
2323
from homeassistant.config_entries import ConfigEntry, ConfigFlow
2424
from homeassistant.const import CONF_HOST, CONF_MAC, CONF_NAME, CONF_PORT
2525
from homeassistant.core import HomeAssistant, callback
2626
from homeassistant.data_entry_flow import FlowResult
2727
from homeassistant.exceptions import HomeAssistantError
2828
from homeassistant.helpers.selector import EntitySelector, EntitySelectorConfig
29+
from homeassistant.helpers.service_info.zeroconf import ZeroconfServiceInfo
2930

3031
from .const import (
3132
CONF_ACTIVITIES_AS_SWITCHES,
@@ -40,17 +41,15 @@
4041
)
4142
from .helpers import (
4243
IntegrationNotFound,
43-
UnableToExtractMacAddress,
44-
UnableToDetermineUser,
4544
InvalidWebsocketAddress,
45+
UnableToDetermineUser,
4646
connect_integration,
4747
device_info_from_discovery_info,
4848
get_ha_websocket_url,
4949
get_registered_websocket_url,
50-
mac_address_from_discovery_info,
50+
register_system_and_driver,
5151
synchronize_dock_password,
5252
validate_and_register_system_and_driver,
53-
register_system_and_driver,
5453
validate_dock_password,
5554
validate_websocket_address,
5655
)
@@ -169,17 +168,12 @@ async def async_step_zeroconf(self, discovery_info: ZeroconfServiceInfo):
169168
host = discovery_info.ip_address.compressed
170169
port = discovery_info.port
171170
model = discovery_info.properties.get("model")
172-
try:
173-
mac_address = mac_address_from_discovery_info(discovery_info)
174-
except UnableToExtractMacAddress:
175-
if (
176-
discovery_info.properties.get("model") != "UCR2-simulator"
177-
and discovery_info.properties.get("model") != "UCR3-simulator"
178-
):
179-
return self.async_abort(reason="no_mac")
180-
_LOGGER.debug("Zeroconf from the Simulator %s", discovery_info)
181-
mac_address = SIMULATOR_MAC_ADDRESS.replace(":", "").lower()
182171

172+
(
173+
device_name,
174+
configuration_url,
175+
mac_address,
176+
) = await device_info_from_discovery_info(discovery_info)
183177
remote_name = Remote.name_from_model_id(model)
184178
self.discovery_info.update(
185179
{
@@ -195,10 +189,6 @@ async def async_step_zeroconf(self, discovery_info: ZeroconfServiceInfo):
195189
if mac_address:
196190
await self._async_set_unique_id_and_abort_if_already_configured(mac_address)
197191

198-
device_name, configuration_url = await device_info_from_discovery_info(
199-
discovery_info
200-
)
201-
202192
self.context.update(
203193
{
204194
"title_placeholders": {"name": device_name},

custom_components/unfoldedcircle/helpers.py

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from typing import Any
88
from urllib.parse import urljoin, urlparse
99

10+
from pyUnfoldedCircleRemote.const import SIMULATOR_MAC_ADDRESS
1011
from pyUnfoldedCircleRemote.dock_websocket import DockWebsocket
1112
from pyUnfoldedCircleRemote.remote import (
1213
HTTPError,
@@ -16,9 +17,9 @@
1617
)
1718

1819
from homeassistant.auth.models import TOKEN_TYPE_LONG_LIVED_ACCESS_TOKEN, RefreshToken
19-
from homeassistant.helpers.service_info.zeroconf import ZeroconfServiceInfo
2020
from homeassistant.core import HomeAssistant
2121
from homeassistant.helpers.network import NoURLAvailableError, get_url
22+
from homeassistant.helpers.service_info.zeroconf import ZeroconfServiceInfo
2223

2324
from .const import (
2425
DEFAULT_HASS_URL,
@@ -221,27 +222,15 @@ async def get_registered_websocket_url(remote: Remote) -> str:
221222
return None
222223

223224

224-
@staticmethod
225-
def mac_address_from_discovery_info(discovery_info: ZeroconfServiceInfo) -> str:
226-
"""Returns the mac address embedded in the hostname. This is typically used with zeroconf broadcasts"""
227-
hostname = discovery_info.hostname
228-
name = discovery_info.name
229-
try:
230-
return re.match(r"(?:RemoteTwo|RemoteThree)-(.*?)\.", hostname).group(1).lower()
231-
except Exception:
232-
try:
233-
return re.match(r"(?:RemoteTwo|RemoteThree)-(.*?)\.", name).group(1).lower()
234-
except Exception:
235-
raise UnableToExtractMacAddress
236-
237-
238225
async def device_info_from_discovery_info(discovery_info: ZeroconfServiceInfo) -> tuple:
226+
"""Returns device information from discovery info"""
239227
host = discovery_info.ip_address.compressed
240228
port = discovery_info.port
241229
model = discovery_info.properties.get("model")
242230
endpoint = f"http://{host}:{port}/api/"
243231
configuration_url = ""
244232
device_name = ""
233+
mac_address = ""
245234
match model:
246235
case "UCR2":
247236
device_name = "Remote Two"
@@ -253,13 +242,15 @@ async def device_info_from_discovery_info(discovery_info: ZeroconfServiceInfo) -
253242
device_name = response.get("device_name", None)
254243
if not device_name:
255244
device_name = "Remote Two"
245+
mac_address = response.get("address", "").replace(":", "").lower()
256246
except Exception:
257247
pass
258248
case "UCR2-simulator":
259249
device_name = "Remote Two Simulator"
260250
configuration_url = (
261251
f"http://{discovery_info.host}:{discovery_info.port}/configurator/"
262252
)
253+
mac_address = SIMULATOR_MAC_ADDRESS.replace(":", "").lower()
263254
case "UCR3":
264255
device_name = "Remote 3"
265256
configuration_url = (
@@ -269,15 +260,17 @@ async def device_info_from_discovery_info(discovery_info: ZeroconfServiceInfo) -
269260
response = await Remote.get_version_information(endpoint)
270261
device_name = response.get("device_name", None)
271262
if not device_name:
272-
device_name = "Remote Two"
263+
device_name = "Remote Three"
264+
mac_address = response.get("address", "").replace(":", "").lower()
273265
except Exception:
274266
pass
275267
case "UCR3-simulator":
276268
device_name = "Remote 3 Simulator"
277269
configuration_url = (
278270
f"http://{discovery_info.host}:{discovery_info.port}/configurator/"
279271
)
280-
return device_name, configuration_url
272+
mac_address = SIMULATOR_MAC_ADDRESS.replace(":", "").lower()
273+
return device_name, configuration_url, mac_address
281274

282275

283276
async def validate_tokens(hass: HomeAssistant, remote: Remote) -> bool:

custom_components/unfoldedcircle/manifest.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
"issue_tracker": "https://github.com/JackJPowell/hass-unfoldedcircle/issues",
1111
"requirements": [
1212
"websockets>=12.0,<14",
13-
"pyUnfoldedCircleRemote==0.13.4",
13+
"pyUnfoldedCircleRemote==0.14.0",
1414
"wakeonlan==3.1.0"
1515
],
16-
"version": "0.14.6",
16+
"version": "0.15.0",
1717
"zeroconf": ["_uc-remote._tcp.local."]
1818
}

custom_components/unfoldedcircle/media_player.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
from homeassistant.const import STATE_OFF, STATE_ON
1717
from homeassistant.core import HomeAssistant, callback
1818
from homeassistant.helpers.entity_platform import AddEntitiesCallback
19-
from homeassistant.util import utcnow
2019
from pyUnfoldedCircleRemote.const import RemoteUpdateType
2120
from pyUnfoldedCircleRemote.remote import (
2221
Activity,

custom_components/unfoldedcircle/pyUnfoldedCircleRemote/remote.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -933,7 +933,7 @@ async def get_version(self) -> dict[str]:
933933
await self.get_remote_information()
934934

935935
if self._is_simulator is True:
936-
core = information.get("core", "")
936+
# core = information.get("core", "")
937937
# We only care about the beginning of the version for this compare
938938
self._external_entity_configuration_available = True
939939
self._new_web_configurator = False
@@ -1511,8 +1511,12 @@ async def get_remote_network_settings(self) -> str:
15111511
self._wifi_enabled = settings.get("wifi_enabled")
15121512

15131513
try:
1514-
self._wake_on_lan = settings.get("wake_on_wlan").get("enabled")
1515-
self._wake_on_lan_available = True
1514+
if self._model_number.upper() == "UCR3":
1515+
self._wake_on_lan = False
1516+
self._wake_on_lan_available = False
1517+
else:
1518+
self._wake_on_lan = settings.get("wake_on_wlan").get("enabled")
1519+
self._wake_on_lan_available = True
15161520
except AttributeError:
15171521
self._wake_on_lan = False
15181522
return settings

custom_components/unfoldedcircle/remote.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -482,11 +482,11 @@ async def async_send_command(self, **kwargs: Any) -> None:
482482
port=port,
483483
)
484484
except (AuthenticationError, OSError) as err:
485-
_LOGGER.error("Failed to learn '%s': %s", command, err)
485+
_LOGGER.error("Failed to send '%s': %s", command, err)
486486
break
487487

488488
except Exception as err:
489-
_LOGGER.error("Failed to learn '%s': %s", command, err)
489+
_LOGGER.error("Failed to send '%s': %s", command, err)
490490
continue
491491

492492
def translate_port(self, port_name) -> str:

requirements.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Home Assistant
2-
homeassistant>=2025.2
2+
homeassistant>=2025.5
33
PyTurboJPEG
44

55
# Development
@@ -8,4 +8,5 @@ pip>=24.2
88
ruff>=0.5.3
99
aiohttp_fast_zlib
1010
zlib_ng
11-
isal
11+
isal
12+
pre-commit

0 commit comments

Comments
 (0)