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 custom alarm days #44

Merged
merged 2 commits into from
Sep 30, 2023
Merged
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
3 changes: 3 additions & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
# github: theneweinstein
ko_fi: theneweinstein
58 changes: 33 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,53 +1,61 @@
# Somneo custom component
Home Assistant custom component for Philips Someo. This integration let's you control the light of the Somneo and reads the following sensors: temperature, humidity, luminance and noise. Furthermore, it provides the alarms set on your Somneo instance as binary sensors and provides a sensor with the first upcoming alarm.
# Somneo custom integration
Home Assistant custom integration to control a Philips Somneo device. This integration let's you control:
- The light and nightlight of the Somneo
- All the 16 available alarms (toggle, time, days, powerwake)
- Media player of the Somneo (FM radio or aux. input)
- Snooze or ignore alarm (buttons)

Furthermore, it provides the following sensors:
- Ambient sensors (temperature, humidity, luminance and noise)
- Alarm status (on, off, snooze, wake-up)
- Next alarm

# Installation
You can install this custom component via HACS as a custom repository (https://hacs.xyz/docs/faq/custom_repositories/). Alternatively you can clone or copy the files into the somneo folder in the custom_components folder of HomeAssistant.

# Configuration
Go to: https://my.home-assistant.io/redirect/config_flow_start/?domain=somneo
The Somneo should be automatically detected via SSDP. If not, you can also manually configure the Somneo: https://my.home-assistant.io/redirect/config_flow_start/?domain=somneo.

# Alarm Configuration
### With slider-entity-row from HACS`
Add a "manual" card into lovelace UI and copy paste the following code. It will create a card for the first Somneo Alarm (alarm0).
# Alarm UI configuration
Add a "manual" card into lovelace UI and copy paste the following code. It will create a card for the first Somneo Alarm (alarm0).
Other cards can be created for other alarms (alarm1, alarm2, etc.)
```
type: entities
entities:
- entity: switch.somneo_alarm0
name: On/Off
- type: custom:slider-entity-row
entity: number.somneo_alarm0_hours
hide_state: false
name: Hours
- type: custom:slider-entity-row
entity: number.somneo_alarm0_minutes
hide_state: false
name: Minutes
- entity: time.somneo_alarm0_time
name: Time
- entity: select.somneo_alarm0_days
name: Days
- entity: switch.somneo_alarm0_powerwake
name: PowerWake
- entity: number.somneo_alarm0_powerwake_delay
name: PowerWake delay
title: Alarm work
show_header_toggle: false
```
<img src="https://github.com/theneweinstein/somneo/blob/master/lovelace1.jpg" alt="Example Lovelace Slider" width="80%"/>
<img src="https://github.com/theneweinstein/somneo/blob/master/lovelace1.jpg" alt="Example Lovelace" width="80%"/>

### Without slider-entity-row from HACS
# Custom alarm days

The select entity for the days only supports a limited set of days, namely weekdays, weekends, everyday and tomorrow. In case you want to select a different day for the alarm, you can use the text entity. The text contains a comma-seperated list (without white-spaces) of abbreviations of the day of the week (i.e. `mon,tue,wed,thu,fri,sat,sun`) or `tomorrow`.
```
type: entities
entities:
- entity: switch.somneo_alarm0
name: On/Off
- entity: number.somneo_alarm0_hours
name: Hours
- entity: number.somneo_alarm0_minutes
name: Minutes
- entity: select.somneo_alarm0_days
- entity: time.somneo_alarm0_time
name: Time
- entity: text.somneo_alarm0_days
name: Days
- entity: switch.somneo_alarm0_powerwake
name: PowerWake
- entity: number.somneo_alarm0_powerwake_delay
name: PowerWake delay
title: Alarm work
show_header_toggle: false
```
<img src="https://github.com/theneweinstein/somneo/blob/master/lovelace2.jpg" alt="Example Lovelace" width="80%"/>
<img src="https://github.com/theneweinstein/somneo/blob/master/lovelace2.jpg" alt="Example Lovelace with custom days" width="80%"/>


# Services
This component includes two services to adjust the wake-up light and sound settings. To adjust the light settings of an alarm you can call the following function:
Expand Down Expand Up @@ -85,4 +93,4 @@ target:
service: somneo.remove_alarm
target:
entity_id: switch.somneo_alarm0
```
```
49 changes: 31 additions & 18 deletions custom_components/somneo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
Platform.TIME,
Platform.BUTTON,
Platform.MEDIA_PLAYER,
Platform.TEXT
]
SCAN_INTERVAL = timedelta(seconds=60)

Expand Down Expand Up @@ -210,26 +211,38 @@ async def async_set_snooze_time(self, time):
async def async_set_alarm_day(self, alarm, day):
"""Set the day of the alarm."""
async with self.state_lock:
if day == WORKDAYS:
if type(day) == list:
await self.hass.async_add_executor_job(
self.somneo.set_alarm_workdays, alarm
)
self.somneo.set_alarm_days,
alarm,
day
)
_LOGGER.debug("Optie is werkday")
elif day == WEEKEND:
await self.hass.async_add_executor_job(
self.somneo.set_alarm_weekend, alarm
)
_LOGGER.debug("Optie is weekend")
elif day == TOMORROW:
await self.hass.async_add_executor_job(
self.somneo.set_alarm_tomorrow, alarm
)
_LOGGER.debug("Optie is morgen")
elif day == EVERYDAY:
await self.hass.async_add_executor_job(
self.somneo.set_alarm_everyday, alarm
)
_LOGGER.debug("Optie is elke dag")
else:
if day == WORKDAYS:
await self.hass.async_add_executor_job(
self.somneo.set_alarm_workdays,
alarm
)
_LOGGER.debug("Optie is werkday")
elif day == WEEKEND:
await self.hass.async_add_executor_job(
self.somneo.set_alarm_weekend,
alarm
)
_LOGGER.debug("Optie is weekend")
elif day == TOMORROW:
await self.hass.async_add_executor_job(
self.somneo.set_alarm_tomorrow,
alarm
)
_LOGGER.debug("Optie is morgen")
elif day == EVERYDAY:
await self.hass.async_add_executor_job(
self.somneo.set_alarm_everyday,
alarm
)
_LOGGER.debug("Optie is elke dag")

await self.async_request_refresh()

Expand Down
2 changes: 1 addition & 1 deletion custom_components/somneo/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
WEEKEND: Final = "weekend"
TOMORROW: Final = "tomorrow"
EVERYDAY: Final = "daily"
UNKNOWN: Final = "unknown"
CUSTOM: Final = "custom"
PW_DELTA: Final = "powerwake_delta"

ALARMS_ICON: Final = "hass:alarm"
Expand Down
8 changes: 4 additions & 4 deletions custom_components/somneo/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
"somneo"
],
"requirements": [
"pysomneo==3.0.1"
"pysomneo==3.1.3"
],
"ssdp": [
{
"nt": "urn:philips-com:device:DiProduct:1",
"modelName": "Wake-up Light"
"modelName": "Wake-up Light"
}
],
"version": "5.0.4"
}
"version": "5.1.0"
}
4 changes: 2 additions & 2 deletions custom_components/somneo/select.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.components.select import SelectEntity

from .const import DOMAIN, WORKDAYS, WEEKEND, TOMORROW, EVERYDAY, UNKNOWN, WORKDAYS_ICON
from .const import DOMAIN, WORKDAYS, WEEKEND, TOMORROW, EVERYDAY, CUSTOM, WORKDAYS_ICON
from .entity import SomneoEntity


Expand Down Expand Up @@ -42,7 +42,7 @@ class SomneoDays(SomneoEntity, SelectEntity):
_attr_icon = WORKDAYS_ICON
_attr_assumed_state = False
_attr_available = True
_attr_options = [WORKDAYS, WEEKEND, TOMORROW, EVERYDAY, UNKNOWN]
_attr_options = [WORKDAYS, WEEKEND, TOMORROW, EVERYDAY, CUSTOM]
_attr_current_option = WORKDAYS

def __init__(self, coordinator, unique_id, name, dev_info, alarm):
Expand Down
71 changes: 71 additions & 0 deletions custom_components/somneo/text.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
"""Text entities for Somneo."""
import logging
from typing import Any
import voluptuous as vol

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_NAME
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.components.text import TextEntity
from homeassistant.helpers import config_validation as cv, entity_platform

from .const import (
DOMAIN,
WORKDAYS_ICON
)
from .entity import SomneoEntity


_LOGGER = logging.getLogger(__name__)


async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Add Somneo from config_entry."""

coordinator = hass.data[DOMAIN][config_entry.entry_id]
unique_id = config_entry.unique_id
assert unique_id is not None
name = config_entry.data[CONF_NAME]
device_info = config_entry.data["dev_info"]

alarms = []
for alarm in list(coordinator.data["alarms"]):
alarms.append(
SomneoAlarmDays(coordinator, unique_id, name, device_info, alarm)
)

async_add_entities(alarms, update_before_add=True)


class SomneoAlarmDays(SomneoEntity, TextEntity):
"""Representation of a alarm switch."""

_attr_should_poll = True
_attr_assumed_state = False
_attr_available = True
_attr_icon = WORKDAYS_ICON
_attr_native_value = None
_attr_pattern = "^((tomorrow|mon|tue|wed|thu|fri|sat|sun)(,)?)+$"

def __init__(self, coordinator, unique_id, name, device_info, alarm):
"""Initialize the switches."""
super().__init__(coordinator, unique_id, name, device_info, alarm)

self._attr_translation_key = alarm + '_days_str'
self._alarm = alarm

@callback
def _handle_coordinator_update(self) -> None:
days_list = self.coordinator.data["alarm_day_list"][self._alarm]
self._attr_native_value = ",".join([str(item) for item in days_list if item])

self.async_write_ha_state()

async def async_set_value(self, value: str) -> None:
"""Set the text value."""
await self.coordinator.async_set_alarm_day(self._alarm, value.split(','))
Loading