Skip to content

Commit

Permalink
Release 0.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
JackJPowell committed Nov 22, 2023
1 parent b817dcd commit c7b39e0
Show file tree
Hide file tree
Showing 10 changed files with 316 additions and 22 deletions.
4 changes: 3 additions & 1 deletion custom_components/unfoldedcircle/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from pyUnfoldedCircleRemote.remote import UCRemote as remote

# from . import ucRemote as remote
#from . import ucRemote as remote

from .const import DOMAIN

Expand All @@ -19,6 +19,8 @@
Platform.SENSOR,
Platform.BINARY_SENSOR,
Platform.UPDATE,
Platform.BUTTON,
Platform.REMOTE,
]


Expand Down
27 changes: 19 additions & 8 deletions custom_components/unfoldedcircle/binary_sensor.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
"""Binary sensor platform for mobile_app."""
"""Binary sensor platform for Unfolded Circle"""
from typing import Any
import logging

from homeassistant.components.binary_sensor import BinarySensorEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.device_registry import DeviceInfo
from .const import DOMAIN

from homeassistant.const import (
Expand Down Expand Up @@ -42,6 +43,22 @@ class BinarySensor(BinarySensorEntity):
# https://developers.home-assistant.io/docs/core/entity/sensor
device_class = ATTR_BATTERY_CHARGING

@property
def device_info(self) -> DeviceInfo:
"""Return the device info."""
return DeviceInfo(
identifiers={
# Serial numbers are unique identifiers within a specific domain
(DOMAIN, self._remote.serial_number)
},
name=self._remote.name,
manufacturer=self._remote.manufacturer,
model=self._remote.model_name,
sw_version=self._remote.sw_version,
hw_version=self._remote.hw_revision,
configuration_url=self._remote.configuration_url,
)

def __init__(self, remote):
"""Initialize the sensor."""
self._remote = remote
Expand All @@ -59,10 +76,4 @@ def is_on(self):
return self._remote.is_charging

async def async_update(self) -> None:
await self._remote.update()

# async def async_restore_last_state(self, last_state):
# """Restore previous state."""

# await super().async_restore_last_state(last_state)
# self._config[ATTR_SENSOR_STATE] = last_state.state == STATE_ON
await self._remote.update()
73 changes: 73 additions & 0 deletions custom_components/unfoldedcircle/button.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"""Button for Unfolded Circle"""
from typing import Any
import logging

from homeassistant.components.button import ButtonEntity, ButtonDeviceClass
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.const import EntityCategory
from homeassistant.helpers.device_registry import DeviceInfo
from .const import DOMAIN

_LOGGER = logging.getLogger(__name__)


async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
remote = hass.data[DOMAIN][config_entry.entry_id]

# Verify that passed in configuration works
if not await remote.can_connect():
_LOGGER.error("Could not connect to Remote")
return

# Get Basic Device Information
await remote.update()

new_devices = []
new_devices.append(Button(remote))
if new_devices:
async_add_entities(new_devices)


class Button(ButtonEntity):
"""Representation of a Button entity."""

_attr_entity_category = EntityCategory.CONFIG
_attr_icon = "mdi:gesture-tap-button"
_attr_device_class = ButtonDeviceClass.RESTART

@property
def device_info(self) -> DeviceInfo:
"""Return the device info."""
return DeviceInfo(
identifiers={
# Serial numbers are unique identifiers within a specific domain
(DOMAIN, self._remote.serial_number)
},
name=self._remote.name,
manufacturer=self._remote.manufacturer,
model=self._remote.model_name,
sw_version=self._remote.sw_version,
hw_version=self._remote.hw_revision,
configuration_url=self._remote.configuration_url,
)

def __init__(self, remote):
"""Initialize the sensor."""
self._remote = remote
self._attr_unique_id = f"{self._remote.serial_number}_restart_button"
self._attr_name = f"{self._remote.name} Restart Remote"

@property
def available(self) -> bool:
"""Return if entity is available."""
return self._remote._online

async def async_press(self) -> None:
"""Press the button."""
await self._remote.post_system_command("RESTART")
4 changes: 2 additions & 2 deletions custom_components/unfoldedcircle/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@

from pyUnfoldedCircleRemote.remote import UCRemote

# from . import ucRemote
#from . import ucRemote

from .const import DOMAIN

_LOGGER = logging.getLogger(__name__)

AUTH_APIKEY_NAME = "pyUnfoldedCircle"
AUTH_APIKEY_NAME = "pyUnfoldedCircle-dev"
AUTH_USERNAME = "web-configurator"

STEP_USER_DATA_SCHEMA = vol.Schema(
Expand Down
6 changes: 3 additions & 3 deletions custom_components/unfoldedcircle/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
"codeowners": ["@jackjpowell"],
"config_flow": true,
"dependencies": ["network"],
"version": "0.0.4",
"documentation": "https://github.com/jackjpowell/hass-unfoldedcircle",
"version": "0.1.0",
"documentation": "https://github.com/jackjpowell/hass_unfolded_circle",
"homekit": {},
"integration_type": "device",
"iot_class": "local_polling",
"requirements": ["pyUnfoldedCircleRemote==0.0.10"],
"requirements": ["pyUnfoldedCircleRemote==0.1.2"],
"ssdp": [],
"zeroconf": []
}
98 changes: 98 additions & 0 deletions custom_components/unfoldedcircle/remote.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
"""Remote sensor platform for Unfolded Circle"""
from typing import Any
import logging

from homeassistant.components.remote import RemoteEntity, RemoteEntityFeature, RemoteEntityDescription
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.entity import ToggleEntityDescription
from homeassistant.helpers.device_registry import DeviceInfo
from collections.abc import Iterable
from .const import DOMAIN

from homeassistant.const import (
ATTR_BATTERY_CHARGING,
)

_LOGGER = logging.getLogger(__name__)


async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
remote = hass.data[DOMAIN][config_entry.entry_id]

# Verify that passed in configuration works
if not await remote.can_connect():
_LOGGER.error("Could not connect to Remote")
return

# Get Basic Device Information
await remote.update()
await remote.get_remotes()
await remote.get_remote_codesets()
await remote.get_docks()

new_devices = []
new_devices.append(RemoteSensor(remote))
if new_devices:
async_add_entities(new_devices)


class RemoteSensor(RemoteEntity):
# The class of this device. Note the value should come from the homeassistant.const
# module. More information on the available devices classes can be seen here:
# https://developers.home-assistant.io/docs/core/entity/sensor
_attr_icon = "mdi:remote"
entity_description: ToggleEntityDescription
_attr_supported_features: RemoteEntityFeature = RemoteEntityFeature.ACTIVITY

@property
def device_info(self) -> DeviceInfo:
"""Return the device info."""
return DeviceInfo(
identifiers={
# Serial numbers are unique identifiers within a specific domain
(DOMAIN, self._remote.serial_number)
},
name=self._remote.name,
manufacturer=self._remote.manufacturer,
model=self._remote.model_name,
sw_version=self._remote.sw_version,
hw_version=self._remote.hw_revision,
configuration_url=self._remote.configuration_url,
)

def __init__(self, remote):
"""Initialize the sensor."""
self._remote = remote

# As per the sensor, this must be a unique value within this domain. This is done
# by using the device ID, and appending "_battery"
self._attr_unique_id = f"{self._remote.serial_number}_remote"

# The name of the entity
self._attr_name = f"{self._remote.name} Remote"
self._attr_activity_list = []
self._attr_is_on = False
for activity in self._remote.activities:
self._attr_activity_list.append(activity.name)

async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the entity on."""
self._attr_is_on = True

async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the entity off."""
self._attr_is_on = False

async def async_send_command(self, command: Iterable[str], **kwargs):
for indv_command in command:
await self._remote.send_remote_command(
device=kwargs.get("device"),
command=indv_command,
repeat=kwargs.get("num_repeats"),
)
92 changes: 88 additions & 4 deletions custom_components/unfoldedcircle/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@
DEVICE_CLASS_BATTERY,
DEVICE_CLASS_ILLUMINANCE,
PERCENTAGE,
ATTR_BATTERY_CHARGING,
DATA_MEBIBYTES,
)
from homeassistant.const import EntityCategory
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity import Entity
from homeassistant.components.sensor import SensorStateClass

from .const import DOMAIN

Expand All @@ -38,6 +41,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
new_devices = []
new_devices.append(BatterySensor(remote))
new_devices.append(IlluminanceSensor(remote))
new_devices.append(MemorySensor(remote))
new_devices.append(StorageSensor(remote))
new_devices.append(LoadSensor(remote))
if new_devices:
async_add_entities(new_devices)

Expand All @@ -57,9 +63,20 @@ def __init__(self, remote):
# as name. If name is returned, this entity will then also become a device in the
# HA UI.
@property
def device_info(self):
"""Return information to link this entity with the correct device."""
return {"identifiers": {(DOMAIN, self._remote.serial_number)}}
def device_info(self) -> DeviceInfo:
"""Return the device info."""
return DeviceInfo(
identifiers={
# Serial numbers are unique identifiers within a specific domain
(DOMAIN, self._remote.serial_number)
},
name=self._remote.name,
manufacturer=self._remote.manufacturer,
model=self._remote.model_name,
sw_version=self._remote.sw_version,
hw_version=self._remote.hw_revision,
configuration_url=self._remote.configuration_url,
)

# This property is important to let HA know if this entity is online or not.
# If an entity is offline (return False), the UI will refelect this.
Expand Down Expand Up @@ -159,3 +176,70 @@ def __init__(self, remote):
def state(self):
"""Return the state of the sensor."""
return self._remote.ambient_light_intensity


class MemorySensor(SensorBase):
"""Representation of a Sensor."""

device_class = DATA_MEBIBYTES
_attr_unit_of_measurement = "MiB"
_attr_entity_category = EntityCategory.DIAGNOSTIC

def __init__(self, remote):
"""Initialize the sensor."""
super().__init__(remote)
# As per the sensor, this must be a unique value within this domain. This is done
# by using the device ID, and appending "_battery"
self._attr_unique_id = f"{self._remote.serial_number}_memory_available"

# The name of the entity
self._attr_name = f"{self._remote.name} Memory Available"

@property
def state(self):
"""Return the state of the sensor."""
return self._remote.memory_available


class StorageSensor(SensorBase):
"""Representation of a Sensor."""

device_class = DATA_MEBIBYTES
_attr_unit_of_measurement = "MiB"
_attr_entity_category = EntityCategory.DIAGNOSTIC

def __init__(self, remote):
"""Initialize the sensor."""
super().__init__(remote)
# As per the sensor, this must be a unique value within this domain. This is done
# by using the device ID, and appending "_battery"
self._attr_unique_id = f"{self._remote.serial_number}_storage_available"

# The name of the entity
self._attr_name = f"{self._remote.name} Storage Available"

@property
def state(self):
"""Return the state of the sensor."""
return self._remote.storage_available

class LoadSensor(SensorBase):
"""Representation of a Sensor."""

_attr_unit_of_measurement = "Load"
_attr_entity_category = EntityCategory.DIAGNOSTIC

def __init__(self, remote):
"""Initialize the sensor."""
super().__init__(remote)
# As per the sensor, this must be a unique value within this domain. This is done
# by using the device ID, and appending "_battery"
self._attr_unique_id = f"{self._remote.serial_number}_cpu_load_1_min"

# The name of the entity
self._attr_name = f"{self._remote.name} CPU Load Avg (1 min)"

@property
def state(self):
"""Return the state of the sensor."""
return self._remote._cpu_load.get("one")
Loading

0 comments on commit c7b39e0

Please sign in to comment.