Skip to content

Commit

Permalink
0.20.2
Browse files Browse the repository at this point in the history
- Added HABApp.util.functions with min/max
- Reworked small parts of the file watcher
- Doc improvements
- Dependency updates
  • Loading branch information
spacemanspiff2007 authored Apr 7, 2021
1 parent 26c3b86 commit 301afae
Show file tree
Hide file tree
Showing 30 changed files with 749 additions and 163 deletions.
2 changes: 1 addition & 1 deletion HABApp/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.20.1'
__version__ = '0.20.2'
24 changes: 22 additions & 2 deletions HABApp/core/events/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,15 @@ def __init__(self, value):


class ValueUpdateEvent:
"""
:ivar str ~.name:
:ivar ~.value:
"""

name: str
value: Any

def __init__(self, name=None, value=None):
def __init__(self, name: str = None, value=None):
self.name: str = name
self.value = value

Expand All @@ -23,11 +28,17 @@ def __repr__(self):


class ValueChangeEvent:
"""
:ivar str ~.name:
:ivar ~.value:
:ivar ~.old_value:
"""

name: str
value: Any
old_value: Any

def __init__(self, name=None, value=None, old_value=None):
def __init__(self, name: str = None, value=None, old_value=None):
self.name: str = name
self.value = value
self.old_value = old_value
Expand All @@ -37,6 +48,11 @@ def __repr__(self):


class ItemNoChangeEvent:
"""
:ivar str ~.name:
:ivar Union[int, float] ~.seconds:
"""

name: str
seconds: Union[int, float]

Expand All @@ -49,6 +65,10 @@ def __repr__(self):


class ItemNoUpdateEvent:
"""
:ivar str ~.name:
:ivar Union[int, float] ~.seconds:
"""
name: str
seconds: Union[int, float]

Expand Down
1 change: 1 addition & 0 deletions HABApp/core/files/all.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
LOAD_RUNNING = False


@ignore_exception
def process(files: typing.List[Path], load_next: bool = True):
global LOAD_RUNNING

Expand Down
53 changes: 23 additions & 30 deletions HABApp/core/files/watcher/file_watcher.py
Original file line number Diff line number Diff line change
@@ -1,54 +1,47 @@
import asyncio
import typing
from pathlib import Path
from threading import Lock
from time import time
from typing import Any, Callable, List, Set

import HABApp
from HABApp.core.wrapper import ignore_exception
from .base_watcher import BaseWatcher as __BaseWatcher

LOCK = Lock()

DEBOUNCE_TIME: float = 0.6


class AggregatingAsyncEventHandler(__BaseWatcher):
def __init__(self, folder: Path, func: typing.Callable[[typing.List[Path]], typing.Any], file_ending: str,
def __init__(self, folder: Path, func: Callable[[List[Path]], Any], file_ending: str,
watch_subfolders: bool = False):
super().__init__(folder, file_ending, watch_subfolders=watch_subfolders)

self.func = func

self.__task: typing.Optional[asyncio.Future] = None
self.__files: typing.Set[str] = set()

def __execute(self):
with LOCK:
self.func([Path(f) for f in self.__files])
self.__files.clear()
self._files: Set[Path] = set()
self.last_event: float = 0

@ignore_exception
def file_changed(self, dst: str):
# this has to be thread safe!
with LOCK:
self.__files.add(dst)
# Map from thread to async
asyncio.run_coroutine_threadsafe(self._event_waiter(Path(dst)), loop=HABApp.core.const.loop)

@ignore_exception
async def _event_waiter(self, dst: Path):
self.last_event = ts = time()
self._files.add(dst)

# cancel already running Task
if self.__task is not None:
self.__task.cancel()
# debounce time
await asyncio.sleep(DEBOUNCE_TIME)

# and create a new one
self.__task = asyncio.run_coroutine_threadsafe(self.__event_waiter(), loop=HABApp.core.const.loop)
# check if a new event came
if self.last_event > ts:
return None

@ignore_exception
async def __event_waiter(self):
try:
# debounce time
await asyncio.sleep(0.6)

# trigger file event
self.__task = None
self.__execute()
except asyncio.CancelledError:
pass
# Copy Path so we're done here
files = list(self._files)
self._files.clear()
self.func(files)

def trigger_all(self):
files = HABApp.core.lib.list_files(self.folder, self.file_ending, self.watch_subfolders)
Expand Down
2 changes: 2 additions & 0 deletions HABApp/core/items/item_color.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@


class ColorItem(BaseValueItem):
"""Item for dealing with color related values"""

def __init__(self, name: str, hue=0.0, saturation=0.0, brightness=0.0):
super().__init__(name=name, initial_value=(hue, saturation, brightness))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ class UserThingCfg(BaseModel):
test: bool
filter: List[ThingFilter]
# order of the type hint matters: int, str!
thing_config: Dict[Union[int, str], Union[int, float, str]] = Field(alias='thing config', default_factory=dict)
thing_config: Dict[Union[int, str], Union[int, float, str, List[str]]] = Field(alias='thing config',
default_factory=dict)
create_items: List[UserItemCfg] = Field(alias='create items', default_factory=list)
channels: List[UserChannelCfg] = Field(default_factory=list)

Expand Down
2 changes: 1 addition & 1 deletion HABApp/openhab/events/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
from .channel_events import ChannelTriggeredEvent
from .thing_events import ThingStatusInfoChangedEvent, ThingStatusInfoEvent, \
ThingConfigStatusInfoEvent, ThingFirmwareStatusInfoEvent
from .event_filters import ItemStateChangedEventFilter, ItemStateEventFilter
from .event_filters import ItemStateEventFilter, ItemStateChangedEventFilter
5 changes: 5 additions & 0 deletions HABApp/openhab/events/channel_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@


class ChannelTriggeredEvent(OpenhabEvent):
"""
:ivar str ~.name:
:ivar str ~.event:
:ivar str ~.channel:
"""
name: str
event: str
channel: str
Expand Down
34 changes: 34 additions & 0 deletions HABApp/openhab/events/item_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@


class ItemStateEvent(OpenhabEvent, HABApp.core.events.ValueUpdateEvent):
"""
:ivar str ~.name:
:ivar ~.value:
"""
name: str
value: typing.Any

Expand All @@ -31,6 +35,11 @@ def __repr__(self):


class ItemStateChangedEvent(OpenhabEvent, HABApp.core.events.ValueChangeEvent):
"""
:ivar str ~.name:
:ivar ~.value:
:ivar ~.old_value:
"""
name: str
value: typing.Any
old_value: typing.Any
Expand All @@ -56,6 +65,10 @@ def __repr__(self):


class ItemCommandEvent(OpenhabEvent):
"""
:ivar str ~.name:
:ivar ~.value:
"""
name: str
value: typing.Any

Expand All @@ -75,6 +88,10 @@ def __repr__(self):


class ItemAddedEvent(OpenhabEvent):
"""
:ivar str ~.name:
:ivar str ~.type:
"""
name: str
type: str

Expand All @@ -96,6 +113,10 @@ def __repr__(self):


class ItemUpdatedEvent(OpenhabEvent):
"""
:ivar str ~.name:
:ivar str ~.type:
"""
name: str
type: str

Expand All @@ -118,6 +139,9 @@ def __repr__(self):


class ItemRemovedEvent(OpenhabEvent):
"""
:ivar str ~.name:
"""
name: str

def __init__(self, name: str = ''):
Expand All @@ -135,6 +159,10 @@ def __repr__(self):


class ItemStatePredictedEvent(OpenhabEvent):
"""
:ivar str ~.name:
:ivar ~.value:
"""
name: str
value: typing.Any

Expand All @@ -155,6 +183,12 @@ def __repr__(self):


class GroupItemStateChangedEvent(OpenhabEvent):
"""
:ivar str ~.name:
:ivar str ~.item:
:ivar ~.value:
:ivar ~.old_value:
"""
name: str
item: str
value: typing.Any
Expand Down
20 changes: 20 additions & 0 deletions HABApp/openhab/events/thing_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@


class ThingStatusInfoEvent(OpenhabEvent):
"""
:ivar str ~.name:
:ivar str ~.status:
:ivar str ~.detail:
"""
name: str
status: str
detail: str
Expand All @@ -30,6 +35,13 @@ def __repr__(self):


class ThingStatusInfoChangedEvent(OpenhabEvent):
"""
:ivar str ~.name:
:ivar str ~.status:
:ivar str ~.detail:
:ivar str ~.old_status:
:ivar str ~.old_detail:
"""
name: str
status: str
detail: str
Expand Down Expand Up @@ -62,6 +74,10 @@ def __repr__(self):


class ThingConfigStatusInfoEvent(OpenhabEvent):
"""
:ivar str ~.name:
:ivar list ~.messages:
"""
name: str
messages: typing.List[typing.Dict[str, str]]

Expand All @@ -81,6 +97,10 @@ def __repr__(self):


class ThingFirmwareStatusInfoEvent(OpenhabEvent):
"""
:ivar str ~.name:
:ivar str ~.status:
"""
name: str
status: str

Expand Down
3 changes: 2 additions & 1 deletion HABApp/util/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from . import functions
from .counter_item import CounterItem
from .period_counter import PeriodCounter
from .threshold import Threshold
from .statistics import Statistics
from . import multimode

# 27.04.2020 - this can be removed in some time
from .multimode import MultiModeItem
from .multimode import MultiModeItem
1 change: 1 addition & 0 deletions HABApp/util/functions/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .min_max import min, max
30 changes: 30 additions & 0 deletions HABApp/util/functions/min_max.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from builtins import max as _max
from builtins import min as _min


def max(*args, default=None):
"""Behaves like the built in max function but ignores any ``None`` values. e.g. ``max([1, None, 2]) == 2``.
If the iterable is empty ``default`` will be returned.
:param args: Single iterable or 1..n arguments
:param default: Value that will be returned if the iterable is empty
:return: max value
"""
return _max(
filter(lambda x: x is not None, args[0] if len(args) == 1 else args),
default=default
)


def min(*args, default=None):
"""Behaves like the built in min function but ignores any ``None`` values. e.g. ``min([1, None, 2]) == 1``.
If the iterable is empty ``default`` will be returned.
:param args: Single iterable or 1..n arguments
:param default: Value that will be returned if the iterable is empty
:return: min value
"""
return _min(
filter(lambda x: x is not None, args[0] if len(args) == 1 else args),
default=default
)
21 changes: 11 additions & 10 deletions HABApp/util/multimode/mode_switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,17 @@ class SwitchItemValueMode(ValueMode):
"""SwitchItemMode, same as ValueMode but enabled/disabled of the mode is controlled by a OpenHAB
:class:`~HABApp.openhab.items.SwitchItem`
:ivar datetime.datetime last_update: Timestamp of the last update/enable of this value
:ivar typing.Optional[datetime.timedelta] auto_disable_after: Automatically disable this mode after
a given timedelta on the next recalculation
:vartype auto_disable_func: typing.Optional[typing.Callable[[typing.Any, typing.Any], bool]]
:ivar auto_disable_func: Function which can be used to disable this mode. Any function that accepts two
Arguments can be used. First arg is value with lower priority, second argument is own value.
Return ``True`` to disable this mode.
:vartype calc_value_func: typing.Optional[typing.Callable[[typing.Any, typing.Any], typing.Any]]
:ivar calc_value_func: Function to calculate the new value (e.g. ``min`` or ``max``). Any function that accepts two
Arguments can be used. First arg is value with lower priority, second argument is own value.
:ivar datetime.datetime ~.last_update: Timestamp of the last update/enable of this value
:ivar typing.Optional[datetime.timedelta] ~.auto_disable_after: Automatically disable this mode after
a given timedelta on the next recalculation
:vartype ~.auto_disable_func: typing.Optional[typing.Callable[[typing.Any, typing.Any], bool]]
:ivar ~.auto_disable_func: Function which can be used to disable this mode. Any function that accepts two
Arguments can be used. First arg is value with lower priority,
second argument is own value. Return ``True`` to disable this mode.
:vartype ~.calc_value_func: typing.Optional[typing.Callable[[typing.Any, typing.Any], typing.Any]]
:ivar ~.calc_value_func: Function to calculate the new value (e.g. ``min`` or ``max``). Any function that accepts
two Arguments can be used. First arg is value with lower priority,
second argument is own value.
"""

def __init__(self, name: str,
Expand Down
Loading

0 comments on commit 301afae

Please sign in to comment.