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 long press and release event support #60

Merged
merged 8 commits into from
Apr 22, 2024
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
48 changes: 47 additions & 1 deletion custom_components/button_plus/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,29 @@
from __future__ import annotations

import logging
from datetime import timedelta
from functools import cached_property
from typing import Any

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.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import (
AddEntitiesCallback,
async_get_current_platform,
)

from .button_plus_api.model import Connector, ConnectorEnum
from .const import DOMAIN
from . import ButtonPlusHub

_LOGGER = logging.getLogger(__name__)

SCAN_INTERVAL = timedelta(seconds=30)
SERVICE_LONG_PRESS = "long_press"
SERVICE_RELEASE = "release"


async def async_setup_entry(
hass: HomeAssistant,
Expand Down Expand Up @@ -47,8 +57,23 @@ async def async_setup_entry(

async_add_entities(button_entities)

platform = async_get_current_platform()
platform.async_register_entity_service(
SERVICE_LONG_PRESS,
{},
"_async_long_press_action",
)

platform.async_register_entity_service(
SERVICE_RELEASE,
{},
"_async_release_action",
)


class ButtonPlusButton(ButtonEntity):
_attr_click_type: str | None = None

def __init__(self, btn_id: int, hub: ButtonPlusHub):
self._is_on = False
self._hub_id = hub.hub_id
Expand Down Expand Up @@ -107,3 +132,24 @@ def device_info(self) -> DeviceInfo:
async def async_press(self) -> None:
"""Handle the button press."""
_LOGGER.debug(f"async press from mqtt button: {self._btn_id}")

async def _async_long_press_action(self) -> None:
self._attr_click_type = "long"
await super()._async_press_action()

async def _async_press_action(self) -> None:
self._attr_click_type = "single"
await super()._async_press_action()

async def _async_release_action(self) -> None:
bolkedebruin marked this conversation as resolved.
Show resolved Hide resolved
pass

@property
def state_attributes(self) -> dict[str, Any] | None:
return {
"click_type": self._attr_click_type,
}

@cached_property
def click_type(self) -> str | None:
return self._attr_click_type
8 changes: 8 additions & 0 deletions custom_components/button_plus/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,14 @@ def add_topics_to_buttons(
}
)

# Create topics for button click
button.topics.append({
"brokerid": "ha-button-plus",
"topic": f"buttonplus/{device_id}/button/{button.button_id}/long_press",
"payload": "press",
"eventtype": EventType.LONG_PRESS
})

return device_config

def get_mqtt_endpoint(self, endpoint: str) -> str:
Expand Down
51 changes: 29 additions & 22 deletions custom_components/button_plus/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,33 +29,25 @@ def __init__(self, hass: HomeAssistant, hub: ButtonPlusHub):
self.hub = hub
self._hass = hass
self._mqtt_subscribed_buttons = False
self._mqtt_topic_buttons = f"buttonplus/{hub.hub_id}/button/+/click"
self._mqtt_topic_brightness = f"buttonplus/{hub.hub_id}/brightness/+"
self._mqtt_topic_page = f"buttonplus/{hub.hub_id}/page/+"
self._mqtt_topics = [
(f"buttonplus/{hub.hub_id}/button/+/click", self.mqtt_button_callback),
(f"buttonplus/{hub.hub_id}/button/+/long_press", self.mqtt_button_long_press_callback),
(f"buttonplus/{hub.hub_id}/brightness/+", self.mqtt_brightness_callback),
(f"buttonplus/{hub.hub_id}/page/+", self.mqtt_page_callback),
]

async def _async_update_data(self):
"""Create MQTT subscriptions for buttonplus"""
_LOGGER.debug("Initial data fetch from coordinator")
if not self._mqtt_subscribed_buttons:
self.unsubscribe_mqtt = await mqtt.async_subscribe(
self._hass, self._mqtt_topic_buttons, self.mqtt_button_callback, 0
)
_LOGGER.debug(f"MQTT subscribed to {self._mqtt_topic_buttons}")

if not self._mqtt_subscribed_buttons:
self.unsubscribe_mqtt = await mqtt.async_subscribe(
self._hass,
self._mqtt_topic_brightness,
self.mqtt_brightness_callback,
0,
)
_LOGGER.debug(f"MQTT subscribed to {self._mqtt_topic_brightness}")

if not self._mqtt_subscribed_buttons:
self.unsubscribe_mqtt = await mqtt.async_subscribe(
self._hass, self._mqtt_topic_page, self.mqtt_page_callback, 0
)
_LOGGER.debug(f"MQTT subscribed to {self._mqtt_topic_page}")
for topic, cb in self._mqtt_topics:
self.unsubscribe_mqtt = await mqtt.async_subscribe(
self._hass,
topic,
cb,
0
)
_LOGGER.debug(f"MQTT subscribed to {topic}")

@callback
async def mqtt_page_callback(self, message: ReceiveMessage):
Expand Down Expand Up @@ -92,3 +84,18 @@ async def mqtt_button_callback(self, message: ReceiveMessage):
await self.hass.services.async_call(
"button", "press", target={"entity_id": entity.entity_id}
)

@callback
async def mqtt_button_long_press_callback(self, message: ReceiveMessage):
# Handle the message here
_LOGGER.debug(f"Received message on topic {message.topic}: {message.payload}")
match = re.search(r'/(\d+)/long_press', message.topic)
btn_id = int(match.group(1)) if match else None

entity: ButtonEntity = self.hub.button_entities[str(btn_id)]

await self.hass.services.async_call(
DOMAIN,
'long_press',
target={"entity_id": entity.entity_id}
)
10 changes: 10 additions & 0 deletions custom_components/button_plus/services.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
long_press:
description: Long press of a button on a Button+
target:
entity:
domain: button_plus
release:
description: Release of a button on a Button+
target:
entity:
domain: button_plus
60 changes: 60 additions & 0 deletions custom_components/button_plus/strings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{
"config": {
"abort": {
"mqtt_not_enabled": "The MQTT integration is not enabled. Please add this first here: {mqtt_integration_link}"
},
"error": {
"cannot_connect": "Failed to connect, see log for more info",
"button_plus_connection": "Error connecting or reading from https://api.button.plus/ See log for more info",
"invalid_ip": "The IP ' {ip} ' is not a valid IPv4 address."
},
"step": {
"fetch_website": {
"data": {
"cookie": "Auth Cookie",
"email": "Email",
"password": "Password"
},
"data_description": {
"cookie": "Optional, can be used instead of login. If used, paste the entire cookie content including auth_cookie="
},
"description": "Either enter your login info for button plus or enter the Auth Cookie after login in on https://button.plus/"
},
"manual": {
"data": {
"ip_address": "IP Address"
},
"data_description": {
"ip_address": "Button+ IP address (as seen on the bottom left of the display)"
},
"description": "Manually enter Button+ device IP address"
},
"user": {
"data": {
"broker": "Address to reach the broker."
},
"data_description": {
"broker": "Leave this unchanged if you're unsure what this is."
},
"description": "The MQTT broker configured in Home Assistant will be used:\n - Broker: {mqtt_broker}\n - Port:{mqtt_broker_port}\n - Authentication: {mqtt_user}\n\n This broker configuration will be added to each device with the name of this integration; 'ha-button-plus' and can be found in the Button+ interface.\n\n The buttons of the Button+ will be configured to send clicks on a topic in this broker and the integration will sync these with the home assistant button entities. \n\n You can override the MQTT broker endpoint if you want here."
},
"choose_entry": {
"menu_options": {
"fetch_website": "Fetch all devices from Button.plus website",
"manual": "Manually enter single device by local IP"
},
"description": "To continue, pick the desired option to setup your Button+ devices."
}
}
},
"services": {
"long_press": {
"name": "Long press",
"description": "Long press on a button on button+"
},
"release": {
"name": "Release",
"description": "Release of a button on button+"
}
}
}
10 changes: 10 additions & 0 deletions custom_components/button_plus/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,15 @@
"description": "To continue, pick the desired option to setup your Button+ devices."
}
}
},
"services": {
"long_press": {
"name": "Long press",
"description": "Long press on a button on button+"
},
"release": {
"name": "Release",
"description": "Release of a button on button+"
}
}
}
Loading