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()
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()