Skip to content

Commit

Permalink
0.19.0
Browse files Browse the repository at this point in the history
- MQTT creates items in HABApp only for messages with persist. Events still get created, even if the item does not exist.
  This shouldn't be but could be a braking change.
- Removed many deprecated functions
- HABApp will now use the openhab log folder as a log-default when started for the first time on a openhabian installation
- Reworked MQTT connection so it is now a module, too (Item/Rule interface stays the same)
- Better error message when rule files are executed outside of HABApp
- Added lots of documentation
  • Loading branch information
spacemanspiff2007 authored Jan 7, 2021
1 parent 42da4ad commit de5f8f5
Show file tree
Hide file tree
Showing 29 changed files with 456 additions and 390 deletions.
2 changes: 1 addition & 1 deletion HABApp/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.18.1'
__version__ = '0.19.0'
7 changes: 4 additions & 3 deletions HABApp/config/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,20 @@
import sys
from pathlib import Path

from EasyCo import ConfigFile, PathContainer, ConfigEntry
from EasyCo import ConfigEntry, ConfigFile, PathContainer

from ._conf_location import Location
from ._conf_mqtt import Mqtt
from ._conf_openhab import Openhab
from .platform_defaults import get_log_folder

log = logging.getLogger('HABApp.Config')


class Directories(PathContainer):
logging: Path = ConfigEntry(Path('log'), description='Folder where the logs will be written to')
logging: Path = ConfigEntry(get_log_folder(Path('log')), description='Folder where the logs will be written to')
rules: Path = ConfigEntry(Path('rules'), description='Folder from which the rule files will be loaded')
param: Path = ConfigEntry(Path('param'), description='Folder from which the parameter files will be loaded')
param: Path = ConfigEntry(Path('params'), description='Folder from which the parameter files will be loaded')
config: Path = ConfigEntry(Path('config'), description='Folder from which configuration files will be loaded')
lib: Path = ConfigEntry(Path('lib'), description='Folder where additional libraries can be placed')

Expand Down
9 changes: 9 additions & 0 deletions HABApp/config/config_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ def load_log(self):
p = (CONFIG.directories.logging / p).resolve()
handler_cfg['filename'] = str(p)

# make file version optional for config file
log_version_info = True # todo: remove this 06.2021
if 'version' not in cfg:
cfg['version'] = 1
log_version_info = False

# load prepared logging
try:
logging.config.dictConfig(cfg)
Expand All @@ -139,4 +145,7 @@ def load_log(self):
log.error(line)

logging.getLogger('HABApp').info(f'HABApp Version {__version__}')

if log_version_info:
log.info('Entry "version" is no longer required in the logging configuration file')
return None
39 changes: 27 additions & 12 deletions HABApp/config/default_logfile.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@

def get_default_logfile() -> str:
return """version : 1
from string import Template
from .platform_defaults import get_log_folder


def get_default_logfile() -> str:
template = Template("""
formatters:
HABApp_format:
format: '[%(asctime)s] [%(name)25s] %(levelname)8s | %(message)s'
handlers:
# There are several Handlers available:
# logging.handlers.RotatingFileHandler:
# Will rotate when the file reaches a certain size (see python logging documentation for args)
# HABApp.core.lib.handler.MidnightRotatingFileHandler:
# Will wait until the file reaches a certain size and then rotate on midnight
# More handlers:
# https://docs.python.org/3/library/logging.handlers.html#rotatingfilehandler
# - logging.handlers.RotatingFileHandler:
# Will rotate when the file reaches a certain size (see python logging documentation for args)
# - HABApp.core.lib.handler.MidnightRotatingFileHandler:
# Will wait until the file reaches a certain size and then rotate on midnight
# - More handlers:
# https://docs.python.org/3/library/logging.handlers.html#rotatingfilehandler
HABApp_default:
class: HABApp.core.lib.handler.MidnightRotatingFileHandler
filename: 'HABApp.log'
filename: '${HABAPP_FILE}'
maxBytes: 1_048_576
backupCount: 3
Expand All @@ -28,7 +29,7 @@ def get_default_logfile() -> str:
EventFile:
class: HABApp.core.lib.handler.MidnightRotatingFileHandler
filename: 'events.log'
filename: '${EVENT_FILE}'
maxBytes: 1_048_576
backupCount: 3
Expand Down Expand Up @@ -56,4 +57,18 @@ def get_default_logfile() -> str:
- BufferEventFile
propagate: False
"""
""")

# Default values are relative
subs = {'EVENT_FILE': 'events.log', 'HABAPP_FILE': 'HABApp.log'}

# Use abs path and rename events.log if we log in the openhab folder
log_folder = get_log_folder()
if log_folder is not None:
# Absolute so we can log errors if the config is faulty
subs['HABAPP_FILE'] = (log_folder / subs['HABAPP_FILE']).as_posix()

# Keep this relative so it is easier to read in the file
subs['EVENT_FILE'] = 'HABApp_events.log'

return template.substitute(**subs)
13 changes: 13 additions & 0 deletions HABApp/config/platform_defaults.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from pathlib import Path
from typing import Optional


def get_log_folder(default: Optional[Path] = None) -> Optional[Path]:
# As a default we log into the openhab folder
choices = ('/var/log/openhab', '/opt/openhab/userdata/logs')
for choice in choices:
path = Path(choice)
if path.is_dir():
return path

return default
3 changes: 1 addition & 2 deletions HABApp/mqtt/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from . import events
from . import items

from .mqtt_interface import MqttInterface
from .mqtt_interface import MqttConnection
from .interface import subscribe, unsubscribe, publish
1 change: 1 addition & 0 deletions HABApp/mqtt/interface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .mqtt_interface import subscribe, unsubscribe, publish # noqa: F401
11 changes: 6 additions & 5 deletions HABApp/mqtt/items/mqtt_item.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import HABApp.mqtt.mqtt_interface
from HABApp.core import Items
from HABApp.core.items import BaseValueItem
from HABApp.mqtt.mqtt_interface import publish


class MqttBaseItem(BaseValueItem):
Expand All @@ -20,10 +21,10 @@ def get_create_item(cls, name: str, initial_value=None) -> 'MqttItem':
assert isinstance(name, str), type(name)

try:
item = HABApp.core.Items.get_item(name)
except HABApp.core.Items.ItemNotFoundException:
item = Items.get_item(name)
except Items.ItemNotFoundException:
item = cls(name, initial_value)
HABApp.core.Items.add_item(item)
Items.add_item(item)

assert isinstance(item, cls), f'{cls} != {type(item)}'
return item
Expand All @@ -38,4 +39,4 @@ def publish(self, payload, qos: int = None, retain: bool = None):
:return: 0 if successful
"""

return HABApp.mqtt.mqtt_interface.MQTT_INTERFACE.publish(self.name, payload, qos=qos, retain=retain)
return publish(self.name, payload, qos=qos, retain=retain)
22 changes: 12 additions & 10 deletions HABApp/mqtt/items/mqtt_pair_item.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from typing import Optional

import HABApp.mqtt.mqtt_interface
from HABApp.core import Items
from HABApp.mqtt.mqtt_interface import publish
from . import MqttBaseItem


Expand All @@ -14,7 +15,8 @@ def build_write_topic(read_topic: str) -> Optional[str]:


class MqttPairItem(MqttBaseItem):
"""An item that represents both a topic that is read only and a corresponding topic that is used to write values"""
"""An item that represents both a topic that is used to read
and a corresponding topic that is used to write values"""

@classmethod
def get_create_item(cls, name: str, write_topic: Optional[str] = None, initial_value=None) -> 'MqttPairItem':
Expand All @@ -34,14 +36,18 @@ def get_create_item(cls, name: str, write_topic: Optional[str] = None, initial_v
write_topic = build_write_topic(name)

try:
item = HABApp.core.Items.get_item(name)
except HABApp.core.Items.ItemNotFoundException:
item = Items.get_item(name)
except Items.ItemNotFoundException:
item = cls(name, write_topic=write_topic, initial_value=initial_value)
HABApp.core.Items.add_item(item)
Items.add_item(item)

assert isinstance(item, cls), f'{cls} != {type(item)}'
return item

def __init__(self, name: str, initial_value=None, write_topic: Optional[str] = None):
super().__init__(name, initial_value)
self.write_topic: Optional[str] = write_topic

def publish(self, payload, qos: int = None, retain: bool = None):
"""
Publish the payload under the write topic from the item.
Expand All @@ -52,8 +58,4 @@ def publish(self, payload, qos: int = None, retain: bool = None):
:return: 0 if successful
"""

return HABApp.mqtt.mqtt_interface.MQTT_INTERFACE.publish(self.write_topic, payload, qos=qos, retain=retain)

def __init__(self, name: str, initial_value=None, write_topic: Optional[str] = None):
super().__init__(name, initial_value)
self.write_topic: Optional[str] = write_topic
return publish(self.write_topic, payload, qos=qos, retain=retain)
Loading

0 comments on commit de5f8f5

Please sign in to comment.