Exemple #1
0
class Bell(ComponentSensor):
    def __init__(self,
                 pin,
                 debounce_time,
                 on_time=None,
                 direction=None,
                 pull_up=True,
                 friendly_name=None,
                 friendly_name_last=None,
                 confirmations=1,
                 ac_signal=False,
                 **kwargs):
        global _unit_index
        _unit_index += 1
        super().__init__(COMPONENT_NAME,
                         __version__,
                         _unit_index,
                         logger=_log,
                         interval_reading=0.001,
                         interval_publish=0.001,
                         expose_intervals=False,
                         **kwargs)
        self._PIN_BELL_IRQ_DIRECTION = direction or machine.Pin.IRQ_FALLING
        self._debounce_time = debounce_time
        self._on_time = on_time or 500
        self._event_bell = EventISR(delay_ms=10)
        self._pin_bell = Pin(pin, machine.Pin.IN,
                             machine.Pin.PULL_UP if pull_up else None)
        self._pin_bell.irq(trigger=self._PIN_BELL_IRQ_DIRECTION,
                           handler=self.__irqBell)
        self._timer_delay = 0
        self._last_activation = 0
        self._confirmations = confirmations
        self._ac = ac_signal
        gc.collect()
        self._addSensorType("bell",
                            friendly_name=friendly_name,
                            binary_sensor=True,
                            discovery_type=_DISCOVERY_BELL,
                            retained_publication=True,
                            topic=_mqtt.getDeviceTopic("bell{!s}".format(
                                self._count)))
        self._addSensorType("last_bell",
                            friendly_name=friendly_name_last,
                            topic=_mqtt.getDeviceTopic("last_bell{!s}".format(
                                self._count)),
                            discovery_type=DISCOVERY_TIMELAPSE,
                            retained_publication=True)
        _log.info("Bell initialized")
        gc.collect()

    async def _read(self):
        if self._event_bell.is_set():
            # if event is set, wait the on_time and reset the state to publish "off"
            await asyncio.sleep_ms(
                self._on_time -
                time.ticks_diff(time.ticks_ms(), self.getTimestamp("bell")))
            await self._setValue("bell", False)
            self._event_bell.clear()
            # print(time.ticks_us(), "loop cleared event")
            return
        # print(time.ticks_us(), "loop awaiting event")
        await self._event_bell.wait()
        # print(time.ticks_us(), "loop got event")
        sl = int(self._debounce_time /
                 self._confirmations) if self._confirmations > 0 else 0
        confirmations = 0
        for _ in range(0, self._confirmations):
            diff = time.ticks_diff(time.ticks_us(), self._timer_delay)
            value = self._pin_bell.value()
            # print(time.ticks_us(), "Timer took", diff / 1000, "ms, pin value", value)
            if not self._ac and (
                    self._PIN_BELL_IRQ_DIRECTION == machine.Pin.IRQ_FALLING and value == 1 \
                    or self._PIN_BELL_IRQ_DIRECTION == machine.Pin.IRQ_RISING and value == 0):
                # print(time.ticks_us(), "pin value didn't stay")
                self._event_bell.clear()
                return False  # return False so no value gets published
            elif self._ac and (
                    self._PIN_BELL_IRQ_DIRECTION == machine.Pin.IRQ_FALLING and value == 0 \
                    or self._PIN_BELL_IRQ_DIRECTION == machine.Pin.IRQ_RISING and value == 1):
                confirmations += 1
            self._timer_delay = time.ticks_us()
            await asyncio.sleep_ms(sl)
        # print(self._ac, confirmations, self._confirmations)
        if self._ac:
            if confirmations > 0:
                # print(time.ticks_us(), "ac signal confirmed")
                pass
            else:
                # print(time.ticks_us(), "no ac signal, only irq")
                self._event_bell.clear()
                return False
        # print(time.ticks_us(), "irq confirmed")
        diff = time.ticks_diff(time.ticks_ms(), self._last_activation)
        if diff > 10000:
            _log.error("Bell rang {!s}s ago, not activated ringing".format(
                diff / 1000))
            self._event_bell.clear()
            return False  # return False so no value gets published
        await self._setValue("bell", True)
        t = time.localtime()
        await self._setValue(
            "last_bell", "{}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(
                t[0], t[1], t[2], t[3], t[4], t[5]))
        if diff > 500:
            _log.warn(
                "Bell rang {!s}ms ago, activated ringing anyways".format(diff))

    def __irqBell(self, p):
        # print(time.ticks_us(), "irq bell", self._event_bell.is_set())
        if self._event_bell.is_set() is True:
            return
        # print("event set")
        self._timer_delay = time.ticks_us()
        self._event_bell.set()
        self._last_activation = time.ticks_ms()
Exemple #2
0
class Bell(Component):
    def __init__(self, pin, debounce_time, on_time=None, irq_direction=None, mqtt_topic=None, friendly_name=None,
                 friendly_name_last=None):
        super().__init__()
        self._topic = mqtt_topic or _mqtt.getDeviceTopic(_component_name)
        self._PIN_BELL_IRQ_DIRECTION = irq_direction or machine.Pin.IRQ_FALLING
        self._debounce_time = debounce_time
        self._on_time = on_time or 500
        self._pin_bell = pin
        self._last_activation = 0
        self._frn = friendly_name
        self._frn_l = friendly_name_last

    async def _init(self):
        await super()._init()
        if self._PIN_BELL_IRQ_DIRECTION == machine.Pin.IRQ_FALLING:
            self._pin_bell = Pin(self._pin_bell, machine.Pin.IN, machine.Pin.PULL_UP)
        else:
            self._pin_bell = Pin(self._pin_bell, machine.Pin.IN)
        self._event_bell = Event()
        self._timer_lock = Lock()
        irq = self._pin_bell.irq(trigger=self._PIN_BELL_IRQ_DIRECTION, handler=self.__irqBell)
        self._event_bell.clear()
        asyncio.get_event_loop().create_task(self.__bell())
        self._timer_bell = machine.Timer(1)
        await _log.asyncLog("info", "Bell initialized")
        gc.collect()

    async def __bell(self):
        while True:
            await self._event_bell
            diff = time.ticks_diff(time.ticks_ms(), self._last_activation)
            if diff > 10000:
                _log.error("Bell rang {!s}s ago, not activated ringing".format(diff / 1000))
                self._event_bell.clear()
                return
            else:
                await _mqtt.publish(self._topic, "ON", qos=1)
                await asyncio.sleep_ms(self._on_time)
                await _mqtt.publish(self._topic, "OFF", qos=1, retain=True)
                if config.RTC_SYNC_ACTIVE:
                    t = time.localtime()
                    await _mqtt.publish(_mqtt.getDeviceTopic("last_bell"),
                                        "{}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(t[0],
                                                                                       t[1], t[2],
                                                                                       t[3], t[4],
                                                                                       t[5]),
                                        qos=1, retain=True)
                self._event_bell.clear()
                if diff > 500:
                    _log.warn("Bell rang {!s}ms ago, activated ringing".format(diff))

    def __irqBell(self, p):
        if self._timer_lock.locked() is True or self._event_bell.is_set() is True:
            return
        else:
            self._timer_lock.acquire()  # not checking return value as we checked locked state above
            self._timer_bell.init(period=self._debounce_time,
                                  mode=machine.Timer.ONE_SHOT, callback=self.__irqTime)

    def __irqTime(self, t):
        if self._PIN_BELL_IRQ_DIRECTION == machine.Pin.IRQ_FALLING and self._pin_bell.value() == 0:
            self._last_activation = time.ticks_ms()
            self._event_bell.set()
        elif self._PIN_BELL_IRQ_DIRECTION == machine.Pin.IRQ_RISING and self._pin_bell.value() == 1:
            self._last_activation = time.ticks_ms()
            self._event_bell.set()
        self._timer_bell.deinit()
        self._timer_lock.release()

    async def _discovery(self):
        await self._publishDiscovery("binary_sensor", self._topic, "bell", '"ic":"mdi:bell",', "Doorbell", self._frn)
        gc.collect()
        if config.RTC_SYNC_ACTIVE is True:
            await self._publishDiscovery("sensor", _mqtt.getDeviceTopic("last_bell"), "last_bell", TIMELAPSE_TYPE,
                                         "Last Bell", self._frn_l)
            gc.collect()