示例#1
0
def on_sse_event(event_dict: dict):
    try:
        # Lookup corresponding OpenHAB event
        event = get_event(event_dict)

        # Update item in registry BEFORE posting to the event bus
        # so the items have the correct state when we process the event in a rule
        try:
            if isinstance(event, ValueUpdateEvent):
                __item = Items.get_item(
                    event.name
                )  # type: HABApp.core.items.base_item.BaseValueItem
                __item.set_value(event.value)
                EventBus.post_event(event.name, event)
                return None

            if isinstance(event, ThingStatusInfoEvent):
                __thing = Items.get_item(
                    event.name)  # type: HABApp.openhab.items.Thing
                __thing.process_event(event)
                EventBus.post_event(event.name, event)
                return None

            # Workaround because there is no GroupItemStateEvent
            if isinstance(event, GroupItemStateChangedEvent):
                __item = Items.get_item(
                    event.name)  # type: HABApp.openhab.items.GroupItem
                __item.set_value(event.value)
                EventBus.post_event(event.name, event)
                return None
        except ItemNotFoundException:
            log_warning(
                log,
                f'Received {event.__class__.__name__} for {event.name} but item does not exist!'
            )

            # Post the event anyway
            EventBus.post_event(event.name, event)
            return None

        if isinstance(event, ItemRemovedEvent):
            remove_from_registry(event.name)
            EventBus.post_event(event.name, event)
            return None

        # These events require that we query openhab because of the metadata so we have to do it in a task
        # They also change the item registry
        if isinstance(event, (ItemAddedEvent, ItemUpdatedEvent)):
            create_task(item_event(event))
            return None

        HABApp.core.EventBus.post_event(event.name, event)
    except Exception as e:
        process_exception(func=on_sse_event, e=e)
        return None
示例#2
0
    async def unload(self):
        try:
            await self.__class__.UNLOAD_FUNC(self.name, self.path)
        except Exception as e:
            if not isinstance(e, AlreadyHandledFileError):
                process_exception(self.__class__.UNLOAD_FUNC, e, logger=self.LOGGER)
            self.set_state(FileState.FAILED)
            return None

        self.set_state(FileState.REMOVED)
        return None
示例#3
0
    async def load(self):
        assert self.state is FileState.DEPENDENCIES_OK, self.state

        try:
            await self.__class__.LOAD_FUNC(self.name, self.path)
        except Exception as e:
            if not isinstance(e, AlreadyHandledFileError):
                process_exception(self.__class__.LOAD_FUNC, e, logger=self.LOGGER)
            self.set_state(FileState.FAILED)
            return None

        self.set_state(FileState.LOADED)
        return None
示例#4
0
def get_msg_payload(msg: MQTTMessage) -> Tuple[Optional[str], Any]:
    try:
        topic = msg._topic.decode('utf-8')
        raw = msg.payload

        try:
            val = raw.decode("utf-8")
        except UnicodeDecodeError:
            # Payload ist a byte stream
            if log.isEnabledFor(logging.DEBUG):
                log._log(logging.DEBUG, f'{topic} ({msg.qos}): {raw[:20]}...', [])
            return topic, raw

        if log.isEnabledFor(logging.DEBUG):
            log._log(logging.DEBUG, f'{topic} ({msg.qos}): {val}', [])

        # None
        if val == 'none' or val == 'None':
            return topic, None

        # bool
        if val == 'true' or val == 'True':
            return topic, True
        if val == 'false' or val == 'False':
            return topic, False

        # int
        if val.isdecimal():
            return topic, int(val)

        # json list/dict
        if val.startswith('{') and val.endswith('}') or val.startswith('[') and val.endswith(']'):
            try:
                return topic, load_json(val)
            except ValueError:
                return topic, val

        # float or str
        try:
            return topic, float(val)
        except ValueError:
            return topic, val
    except Exception as e:
        process_exception('get_msg_payload', e, logger=log)
        return None, None
示例#5
0
    async def start(self, config_folder: Path):
        try:
            token = async_context.set('HABApp startup')

            # setup exception handler for the scheduler
            eascheduler.set_exception_handler(lambda x: process_exception('HABApp.scheduler', x))

            # Start Folder watcher!
            HABApp.core.files.watcher.start()

            self.config_loader = HABApp.config.HABAppConfigLoader(config_folder)

            await HABApp.core.files.setup()

            # generic HTTP
            await HABApp.rule.interfaces._http.create_client()

            # openhab
            openhab_connection.setup()

            # Parameter Files
            await HABApp.parameters.parameter_files.setup_param_files()

            # Rule engine
            self.rule_manager = HABApp.rule_manager.RuleManager(self)
            await self.rule_manager.setup()

            # MQTT
            HABApp.mqtt.mqtt_connection.setup()
            HABApp.mqtt.mqtt_connection.connect()

            await openhab_connection.start()

            shutdown.register_func(HABApp.core.const.loop.stop, msg='Stopping asyncio loop')

            async_context.reset(token)
        except asyncio.CancelledError:
            pass
        except Exception as e:
            process_exception('Runtime.start', e)
            await asyncio.sleep(1)  # Sleep so we can do a graceful shutdown
            shutdown.request_shutdown()
示例#6
0
def map_item(name, openhab_type: str,
             openhab_value: str) -> typing.Optional[BaseItem]:
    try:
        assert isinstance(openhab_type, str), type(openhab_type)
        assert isinstance(openhab_value, str), type(openhab_value)

        value: typing.Optional[str] = openhab_value
        if openhab_value == 'NULL' or openhab_value == 'UNDEF':
            value = None

        # Quantity types are like this: Number:Temperature and have a unit set: "12.3 °C".
        # We have to remove the dimension from the type and remove the unit from the value
        if ':' in openhab_type:
            openhab_type, dimension = openhab_type.split(':')
            # if the item is not initialized its None and has no dimension
            if value is not None:
                value, _ = QuantityValue.split_unit(value)

        # Specific classes
        if openhab_type == "Switch":
            return SwitchItem(name, value)

        if openhab_type == "String":
            return StringItem(name, value)

        if openhab_type == "Contact":
            return ContactItem(name, value)

        if openhab_type == "Rollershutter":
            if value is None:
                return RollershutterItem(name, value)
            return RollershutterItem(name, float(value))

        if openhab_type == "Dimmer":
            if value is None:
                return DimmerItem(name, value)
            return DimmerItem(name, float(value))

        if openhab_type == "Number":
            if value is None:
                return NumberItem(name, value)

            # Number items can be int or float
            try:
                return NumberItem(name, int(value))
            except ValueError:
                return NumberItem(name, float(value))

        if openhab_type == "DateTime":
            if value is None:
                return DatetimeItem(name, value)
            dt = datetime.datetime.strptime(value.replace('+', '000+'),
                                            '%Y-%m-%dT%H:%M:%S.%f%z')
            # all datetimes from openhab have a timezone set so we can't easily compare them
            # --> TypeError: can't compare offset-naive and offset-aware datetimes
            dt = dt.astimezone(
                tz=None)  # Changes datetime object so it uses system timezone
            dt = dt.replace(tzinfo=None)  # Removes timezone awareness
            return DatetimeItem(name, dt)

        if openhab_type == "Color":
            if value is None:
                return ColorItem(name)
            return ColorItem(name, *(float(k) for k in value.split(',')))

        if openhab_type == "Image":
            img = ImageItem(name)
            if value is None:
                return img
            img.set_value(RawValue(value))
            return img

        if openhab_type == "Group":
            return GroupItem(name, value)

        if openhab_type == "Location":
            return LocationItem(name, value)

        if openhab_type == "Player":
            return PlayerItem(name, value)

        raise ValueError(f'Unknown Openhab type: {openhab_type} for {name}')

    except Exception as e:
        process_exception('map_items', e, logger=log)
        return None
示例#7
0
def map_item(name: str, type: str, value: Optional[str],
             tags: FrozenSet[str], groups: FrozenSet[str], metadata: Optional[Dict[str, Dict[str, Any]]]) -> \
        Optional['HABApp.openhab.items.OpenhabItem']:
    try:
        assert isinstance(type, str)
        assert value is None or isinstance(value, str)

        if value == 'NULL' or value == 'UNDEF':
            value = None

        # map Metadata
        if metadata is not None:
            meta = Map({k: MetaData(v['value'], Map(v.get('config', {}))) for k, v in metadata.items()})
        else:
            meta = Map()

        # Quantity types are like this: Number:Temperature and have a unit set: "12.3 °C".
        # We have to remove the dimension from the type and remove the unit from the value
        if ':' in type:
            type, dimension = type.split(':')
            # if the item is not initialized its None and has no dimension
            if value is not None:
                value, _ = QuantityValue.split_unit(value)

        # Specific classes
        if type == "Switch":
            return SwitchItem(name, value, tags=tags, groups=groups, metadata=meta)

        if type == "String":
            return StringItem(name, value, tags=tags, groups=groups, metadata=meta)

        if type == "Contact":
            return ContactItem(name, value, tags=tags, groups=groups, metadata=meta)

        if type == "Rollershutter":
            if value is None:
                return RollershutterItem(name, value, tags=tags, groups=groups, metadata=meta)
            return RollershutterItem(name, float(value), tags=tags, groups=groups, metadata=meta)

        if type == "Dimmer":
            if value is None:
                return DimmerItem(name, value, tags=tags, groups=groups, metadata=meta)
            return DimmerItem(name, float(value), tags=tags, groups=groups, metadata=meta)

        if type == "Number":
            if value is None:
                return NumberItem(name, value, tags=tags, groups=groups, metadata=meta)

            # Number items can be int or float
            try:
                return NumberItem(name, int(value), tags=tags, groups=groups, metadata=meta)
            except ValueError:
                return NumberItem(name, float(value), tags=tags, groups=groups, metadata=meta)

        if type == "DateTime":
            if value is None:
                return DatetimeItem(name, value, tags=tags, groups=groups, metadata=meta)
            # Todo: remove this once we go >= OH3.1
            # Previous OH versions used a datetime string like this:
            # 2018-11-19T09:47:38.284+0100
            # OH 3.1 uses
            # 2021-04-10T22:00:43.043996+0200
            if len(value) == 28:
                value = value.replace('+', '000+')
            dt = datetime.datetime.strptime(value, '%Y-%m-%dT%H:%M:%S.%f%z')
            # all datetimes from openhab have a timezone set so we can't easily compare them
            # --> TypeError: can't compare offset-naive and offset-aware datetimes
            dt = dt.astimezone(tz=None)   # Changes datetime object so it uses system timezone
            dt = dt.replace(tzinfo=None)  # Removes timezone awareness
            return DatetimeItem(name, dt, tags=tags, groups=groups, metadata=meta)

        if type == "Color":
            if value is None:
                return ColorItem(name, tags=tags, groups=groups, metadata=meta)
            return ColorItem(name, *(float(k) for k in value.split(',')), tags=tags, groups=groups, metadata=meta)

        if type == "Image":
            img = ImageItem(name, tags=tags, groups=groups, metadata=meta)
            if value is None:
                return img
            img.set_value(RawValue(value))
            return img

        if type == "Group":
            return GroupItem(name, value, tags=tags, groups=groups, metadata=meta)

        if type == "Location":
            return LocationItem(name, value, tags=tags, groups=groups, metadata=meta)

        if type == "Player":
            return PlayerItem(name, value, tags=tags, groups=groups, metadata=meta)

        raise ValueError(f'Unknown Openhab type: {type} for {name}')

    except Exception as e:
        process_exception('map_items', e, logger=log)
        return None