Skip to content

Commit

Permalink
add duration to event entity
Browse files Browse the repository at this point in the history
  • Loading branch information
pszafer committed Aug 11, 2023
1 parent 0589210 commit 8984100
Show file tree
Hide file tree
Showing 9 changed files with 54 additions and 51 deletions.
6 changes: 4 additions & 2 deletions boneio/bonecli.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from boneio.const import ACTION
from boneio.helper import load_config_from_file
from boneio.helper.exceptions import ConfigurationException, RestartRequestException
from boneio.helper.events import GracefulExit
from boneio.helper.logger import configure_logger
from boneio.runner import async_run
from boneio.version import __version__
Expand Down Expand Up @@ -89,8 +90,9 @@ def run(config: str, debug: int, mqttusername: str = "", mqttpassword: str = "")
),
)
return 0
except RestartRequestException as err:
_LOGGER.info(err)
except (RestartRequestException, GracefulExit) as err:
if err is not None:
_LOGGER.info(err)
return 0
except (ConfigurationException, MarkedYAMLError) as err:
_LOGGER.error("Failed to load config. %s Exiting.", err)
Expand Down
3 changes: 2 additions & 1 deletion boneio/helper/click_timer.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ def reset(self) -> None:
self._remove_listener = None

async def _start_async_timer(self) -> None:
start = time.time()
await asyncio.sleep(self._delay)
self._remove_listener = None
self._action(time.time())
self._action(round(time.time() - start, 2))

def start_timer(self) -> None:
"""Start timer."""
Expand Down
11 changes: 4 additions & 7 deletions boneio/helper/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,19 +77,17 @@ def handle(self):
class EventBus:
"""Simple event bus which ticks every second."""

def __init__(self, last_will_mqtt = Callable) -> None:
def __init__(self, loop: asyncio.AbstractEventLoop) -> None:
"""Initialize handler"""
self._loop = asyncio.get_event_loop()
self._last_will = last_will_mqtt

self._loop = loop or asyncio.get_event_loop()
self._listeners = {}
self._sigterm_listeners = []
self._haonline_listeners = []
self._timer_handle = _async_create_timer(self._loop, self._run_second_event)
for signame in {"SIGINT", "SIGTERM"}:
self._loop.add_signal_handler(
getattr(signal, signame),
lambda: asyncio.create_task(self.ask_exit()),
self.ask_exit,
)

def _run_second_event(self, time):
Expand All @@ -100,15 +98,14 @@ def _run_second_event(self, time):
self._loop.call_soon(listener.target, time)
)

async def ask_exit(self):
def ask_exit(self):
"""Function to call on exit. Should invoke all sigterm listeners."""
_LOGGER.debug("Exiting process started.")
self._listeners = {}
for target in self._sigterm_listeners:
target()
self._timer_handle()

await self._last_will()
_LOGGER.info("Shutdown gracefully.")
raise GracefulExit(code=0)

Expand Down
3 changes: 2 additions & 1 deletion boneio/helper/gpio.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import annotations
import asyncio
import logging

Expand Down Expand Up @@ -104,7 +105,7 @@ class GpioBaseClass:
"""Base class for initialize GPIO"""

def __init__(
self, pin: str, press_callback: Callable[[ClickTypes, str], None], **kwargs
self, pin: str, press_callback: Callable[[ClickTypes, str, bool | None], None], **kwargs
) -> None:
"""Setup GPIO Input Button"""
self._pin = pin
Expand Down
5 changes: 3 additions & 2 deletions boneio/helper/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,12 +349,13 @@ def configure_event_sensor(
GpioEventButtonClass = GpioEventButton if gpio.get("detection_type", "stable") == "stable" else GpioEventButtonBeta
GpioEventButtonClass(
pin=pin,
press_callback=lambda x, i: press_callback(
press_callback=lambda x, i, z: press_callback(
x=x,
inpin=i,
actions=gpio.get(ACTIONS, {}).get(x, []),
input_type=INPUT,
empty_message_after=gpio.get("clear_message", False)
empty_message_after=gpio.get("clear_message", False),
duration=z
),
**gpio,
)
Expand Down
12 changes: 6 additions & 6 deletions boneio/input/gpio_beta.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def __init__(self, **kwargs) -> None:
)
self._timer_long = ClickTimer(
delay=TimePeriod(milliseconds=LONG_PRESS_DURATION_MS),
action=lambda x: self.press_callback(click_type=LONG),
action=lambda x: self.press_callback(click_type=LONG, duration=x),
)
self._double_click_ran = False
self._is_waiting_for_second_click = False
Expand All @@ -52,7 +52,7 @@ def __init__(self, **kwargs) -> None:
def double_click_press_callback(self):
self._is_waiting_for_second_click = False
if not self._state and not self._timer_long.is_waiting():
self.press_callback(click_type=SINGLE)
self.press_callback(click_type=SINGLE, duration=None)

def check_state(self, channel) -> None:
time_now = time.time()
Expand All @@ -65,20 +65,20 @@ def check_state(self, channel) -> None:
if self._timer_double.is_waiting():
self._timer_double.reset()
self._double_click_ran = True
self.press_callback(click_type=DOUBLE)
self.press_callback(click_type=DOUBLE, duration=None)
return
self._timer_double.start_timer()
self._is_waiting_for_second_click = True

else:
if not self._is_waiting_for_second_click and not self._double_click_ran:
if self._timer_long.is_waiting():
self.press_callback(click_type=SINGLE)
self.press_callback(click_type=SINGLE, duration=None)
self._timer_long.reset()
self._double_click_ran = False

def press_callback(self, click_type: ClickTypes):
def press_callback(self, click_type: ClickTypes, duration: float | None = None):
self.click_count = 0
self._loop.call_soon_threadsafe(
partial(self._press_callback, click_type, self._pin)
partial(self._press_callback, click_type, self._pin, duration)
)
17 changes: 12 additions & 5 deletions boneio/manager.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import annotations
import asyncio
import logging
from collections import deque
Expand Down Expand Up @@ -86,7 +87,6 @@ def __init__(
stop_client: Callable[[], Awaitable[None]],
state_manager: StateManager,
config_helper: ConfigHelper,
event_bus: EventBus,
config_file_path: str,
relay_pins: List = [],
event_pins: List = [],
Expand All @@ -111,7 +111,7 @@ def __init__(
self._host_data = None
self._config_file_path = config_file_path
self._state_manager = state_manager
self._event_bus = event_bus
self._event_bus = EventBus(loop=self._loop)

self.send_message = send_message
self.stop_client = stop_client
Expand Down Expand Up @@ -480,13 +480,20 @@ def pcf(self):
return self._pcf

def press_callback(
self, x: ClickTypes, inpin: str, actions: List, input_type: InputTypes = INPUT, empty_message_after: bool = False
self, x: ClickTypes, inpin: str, actions: List, input_type: InputTypes = INPUT, empty_message_after: bool = False, duration: float | None = None
) -> None:
"""Press callback to use in input gpio.
If relay input map is provided also toggle action on relay or cover or mqtt."""
topic = f"{self._config_helper.topic_prefix}/{input_type}/{inpin}"
payload = {"event_type": x} if input_type == INPUT else x
self.send_message(topic=topic, payload=payload, retain=False)

def generate_payload():
if input_type == INPUT:
if duration:
return {"event_type": x, "duration": duration}
return {"event_type": x}
return x

self.send_message(topic=topic, payload=generate_payload(), retain=False)
for action_definition in actions:
_LOGGER.debug("Executing action %s", action_definition)
if action_definition[ACTION] == OUTPUT:
Expand Down
42 changes: 20 additions & 22 deletions boneio/mqtt_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@
from paho.mqtt.properties import Properties
from paho.mqtt.subscribeoptions import SubscribeOptions

from boneio.const import ONLINE, OFFLINE, PAHO, STATE
from boneio.const import OFFLINE, PAHO, STATE
from boneio.helper import UniqueQueue
from boneio.helper.config import ConfigHelper
from boneio.helper.events import GracefulExit
from boneio.manager import Manager
from boneio.helper.exceptions import RestartRequestException

Expand Down Expand Up @@ -58,7 +59,7 @@ def create_client(self) -> None:
self.port,
will=Will(
topic=f"{self._config_helper.topic_prefix}/{STATE}",
payload=ONLINE,
payload=OFFLINE,
qos=0,
retain=False,
),
Expand Down Expand Up @@ -148,33 +149,30 @@ async def _handle_publish(self) -> None:
async def start_client(self, manager: Manager) -> None:
"""Start the client with the manager."""
# Reconnect automatically until the client is stopped.
while True:
try:
await self._subscribe_manager(manager)
except MqttError as err:
self.reconnect_interval = min(self.reconnect_interval * 2, 900)
_LOGGER.error(
"MQTT error: %s. Reconnecting in %s seconds",
err,
self.reconnect_interval,
)
self._connection_established = False
await asyncio.sleep(self.reconnect_interval)
self.create_client() # reset connect/reconnect futures
except asyncio.CancelledError:
_LOGGER.info("MQTT client task canceled.")
try:
while True:
try:
await self._subscribe_manager(manager)
except MqttError as err:
self.reconnect_interval = min(self.reconnect_interval * 2, 900)
_LOGGER.error(
"MQTT error: %s. Reconnecting in %s seconds",
err,
self.reconnect_interval,
)
self._connection_established = False
await asyncio.sleep(self.reconnect_interval)
self.create_client() # reset connect/reconnect futures
except (asyncio.CancelledError, GracefulExit):
_LOGGER.info("MQTT client task canceled.")
pass

async def stop_client(self) -> None:
await self.unsubscribe(
topics=self._topics
)
raise RestartRequestException("Restart requested.")

async def last_will_mqtt(self) -> None:
_LOGGER.info("Sending offline state.")
topic = f"{self._config_helper.topic_prefix}/{STATE}"
self.send_message(topic=topic, payload=OFFLINE, retain=True)

async def _subscribe_manager(self, manager: Manager) -> None:
"""Connect and subscribe to manager topics + host stats."""
async with AsyncExitStack() as stack:
Expand Down
6 changes: 1 addition & 5 deletions boneio/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@ async def async_run(
mqttpassword: str = "",
) -> list[Any]:
"""Run BoneIO."""
_loop = asyncio.get_event_loop()

_config_helper = ConfigHelper(
topic_prefix=config[MQTT].pop(TOPIC_PREFIX),
ha_discovery=config[MQTT][HA_DISCOVERY].pop(ENABLED),
Expand All @@ -74,7 +72,6 @@ async def async_run(
port=config[MQTT].get(PORT, 1883),
config_helper=_config_helper,
)
event_bus = EventBus(last_will_mqtt=client.last_will_mqtt)
manager_kwargs = {
item["name"]: config.get(item["name"], item["default"])
for item in config_modules
Expand All @@ -83,7 +80,6 @@ async def async_run(
manager = Manager(
send_message=client.send_message,
stop_client=client.stop_client,
event_bus=event_bus,
relay_pins=config.get(OUTPUT, []),
event_pins=config.get(EVENT_ENTITY, []),
binary_pins=config.get(BINARY_SENSOR, []),
Expand All @@ -104,4 +100,4 @@ async def async_run(
tasks.update(manager.get_tasks())
_LOGGER.info("Connecting to MQTT.")
tasks.add(client.start_client(manager))
return await asyncio.gather(*tasks)
return await asyncio.gather(*tasks, return_exceptions=True)

0 comments on commit 8984100

Please sign in to comment.