Skip to content

Commit

Permalink
Merge pull request #60 from bolkedebruin/main
Browse files Browse the repository at this point in the history
Add long press and release event support
  • Loading branch information
koenhendriks authored Apr 22, 2024
2 parents 7c28870 + 387df63 commit 6e69da2
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 23 deletions.
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:
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+"
}
}
}

0 comments on commit 6e69da2

Please sign in to comment.