Closed bahmrockk closed 3 years ago
I was able to fix the problem by adding a de-bounce circuit at the input of the GPIO. I'm using the Maxim MAX6817 chip, and it works like a charm. But I feel that this should be fixable through software.
@rarroyo6 as had been previously mentioned, a debounce circuit is not a solution to this issue. Sometimes genuinely short inputs are required for one reason or other, and it is inexcusable that the correct final state is not recorded.
The bounce isn't the problem, the problem is that home assistant frequently misses the final resting state of an input that lasts less than a certain amount of time.
I gave up on this bug getting fixed a long time ago and moved all my inputs to esp chips communicating by mqtt. It's unfortunate that home assistant, for all the things it does so well, is absolutely horrible at the basics of connecting to home devices (see both this, and the state of zwave). It seems that those who design/maintain hass do not use any devices that connect to it by either of those methods.
I do have to say that it is rather silly that this issue is still open and still ignored. I see that there at least 2 pool requests that would (at least partially) solve the problem, and it seems to me that the only reason why non was merged is lack of interest.
So, for those who need this function and are not able to hack the code (not programmers), here is a partial solution that is usable if the application is not extremely critical:
How dose it work: The problem has more parts, but the one making most of the problem is the Raspberry GPIO de-bounce implementation. As pointed out previously in this issue, it is not an actual de-bounce, it is just a 'trigger cut off' in case of state change, that in this particular situation dose more bad than good. So setting the bouncetime to 1 ms reduces to minimum the effect of this filter. Practically only events that are less than 1ms are not reported, so we need the RC filter to make shore that there will be no pulses that are shorter than 1 ms.
I think the debounce logic may indeed be (at least part of) the problem. My GPIO pins are connected to a relay (contactor) with an AC coil. There could be some bounce in the signal. It's all starting to (finally) make sense to me. Rather than register the final state, HA simply gives up after some number of rapid state changes, leaving an almost random result.
It still amazes me that a problem like this can remain for years in a project with so many active developers. I guess it speaks to the level of abstraction most developers are working at. Sometimes all these multiple layers of higher-level languages puts us too far from the underlying hardware.
Yes, incredible that is not resolved
Does anyone know why RPI GPIO7 as a binary sensor does not configure? HA logs say "Failed to add edge detection" causing "platform: rpi_gpio" to fail. If I comment out GPIO7 "7: Bedroom 2 Window", then the remaining GPIO pins work fine. I am on RPI 3 B+ with HAOS 2021.1.5. GPIO7 use to work a year or two ago.
FYI: I resolved the RPI GPIO edge trigger issue by creating a PI Shield PWBA incorporating ATmega328p to do S/W debounce of magnetic relay inputs from doors and windows. I settled on requiring relay inputs to ATmega328p to be stable for 25ms, before reporting HIGH->LOW or LOW->HIGH transitions to GPIO pins. 25ms is plenty fast enough for button and relay inputs, and plenty slow enough for the RPI to respond and not miss an edge. So incorporating S/W debouncing in HA python code is the answer.
binary_sensor:
- platform: rpi_gpio
invert_logic: true
ports:
4: Living Room PIR
5: Living Room Window
6: Bedroom 1 Window
7: Bedroom 2 Window
22: Bedroom 3 Window
23: Bathroom Window
24: Kitchen Window
25: Front Door
26: Sliding Door
27: Carport Door
Just posted a pull request which (hopefully) fixes the problem. No idea whether it'll be accepted or not, so, if you don't want to wait, create the "config/custom_components/rpi_gpio2" directory in your HA installation, extract the attached zip into, change the domain of your gpio binary sensors from "rpi_gpio" to "rpi_gpio2" and restart. It works fine for me; let me know if it does for you.
You saved my day...I can't believe this issue still persist in 2021.
I just wanted to confirm that the rpi_gpio2.zip works for me as well.
When I moved to a RPI4 with harddisk with Rasbian and docker containers, I was no longer able to get any inputs to work from GPIO This rpi_gpio2 fixed it !
A big thank you to @greg2001 I have been chewing on this issue for weeks
Can you elaborate a bit on what you changed?
I'm trying to gauge the impact on my RPI4, but I can't make much sense of https://github.com/greg2001/home-assistant/commit/cfc12d6203acc1796b69ee32851768d78bac7ebe (not being a developer)
Are you re-reading all GPIOs at "_bouncetime/1000"?
Is that the bouncetime that we can configure in the yaml files of Home Assistant?
Great Job ! I can finally move on with my migration to the RPI4
ChrisV
I just wanted to confirm that the rpi_gpio2.zip works for me as well. When I moved to a RPI4 with harddisk with Rasbian and docker containers, I was no longer able to get any inputs to work from GPIO This rpi_gpio2 fixed it !
A big thank you to @greg2001 I have been chewing on this issue for weeks
Thank you for running the test to confirm this works, and I'll add my thanks to @greg2001, too!
Now, how do we get this thing accepted? A year seems a long time to wait.
Hi all I give it a try: I created a PR to have the rpi_gpio2 solution (without threads) to be merged. See above.
I will give it a test this week.
Tested on RPI 3 B+ with HAOS 2021.3.6 with following configuration:
binary_sensor:
Works as desired. Pin states were accurately reported.
I do see this in the log:
BinarySensorDevice is deprecated, modify RPiGPIOBinarySensor to extend BinarySensorEntity March 23, 2021, 8:09:03 PM – Binary sensor (WARNING)
No 'version' key in the manifest file for custom integration 'rpi_gpio2'. This will not be allowed in a future version of Home Assistant. Please report this to the maintainer of 'rpi_gpio2' March 23, 2021, 8:09:03 PM – loader.py (WARNING)
Hi, I think we have a missunderstanding. The warning in the log means you tested the solution out of the older zip file and Not the provided pull request for the homeassistant main repo.
Technically pretty the same but without thread which Blocked the previous PR to be merged
@REALogics also the first error won't occur in the final solution, as BinarySensorEntity
is already used as a base class - https://github.com/home-assistant/core/pull/48170/files#diff-b8f4dc78d24beb32fff650f40c8846f919c1654ab5e68cec459acd6bd61fa97aR55
I hope https://github.com/home-assistant/core/pull/48170 will be merged soon. The next beta will be released on 31 March, so not much time left.
Hi, I have 10 binary sensors in a Raspberry Pi 4 running hassos. I finally had a working system thanks to the rio_gpio2 zip solution, but would really like to have a fix that is merged without the need of the workaround. I am pretty new to home assistant so the only way I found to try to test the pull request is to do something similar to the other workaround using a custom_component. So I created a folder named rio_gpio3. I'll post below the content of the files. I have been running it for around an hour and it seems to be detecting the states correctly, with one glitch. When I restart the server it sometimes raises the following error in the log:
Uncaught exception 8:22:57 – custom_components/rpi_gpio3/binary_sensor.py (ERROR)
The details are:
Logger: root Source: custom_components/rpi_gpio3/binary_sensor.py:81 First occurred: 8:22:57 (1 occurrences) Last logged: 8:22:57
Uncaught exception Traceback (most recent call last): File "/config/custom_components/rpi_gpio3/binary_sensor.py", line 81, in edge_detected self.hass.add_job(self.async_read_gpio) AttributeError: 'NoneType' object has no attribute 'add_job'
Hope this helps
/config/custom_components/rpi_gpio3/__init__.py
"""Support for controlling GPIO pins of a Raspberry Pi."""
import logging
from RPi import GPIO # pylint: disable=import-error
from homeassistant.const import EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP
_LOGGER = logging.getLogger(__name__)
DOMAIN = "rpi_gpio3"
PLATFORMS = ["binary_sensor"]
def setup(hass, config):
"""Set up the Raspberry PI GPIO component."""
def cleanup_gpio(event):
"""Stuff to do before stopping."""
GPIO.cleanup()
def prepare_gpio(event):
"""Stuff to do when Home Assistant starts."""
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, cleanup_gpio)
hass.bus.listen_once(EVENT_HOMEASSISTANT_START, prepare_gpio)
GPIO.setmode(GPIO.BCM)
return True
def setup_output(port):
"""Set up a GPIO as output."""
GPIO.setup(port, GPIO.OUT)
def setup_input(port, pull_mode):
"""Set up a GPIO as input."""
GPIO.setup(port, GPIO.IN, GPIO.PUD_DOWN if pull_mode == "DOWN" else GPIO.PUD_UP)
def write_output(port, value):
"""Write a value to a GPIO."""
GPIO.output(port, value)
def read_input(port):
"""Read a value from a GPIO."""
return GPIO.input(port)
def edge_detect(port, event_callback, bounce):
"""Add detection for RISING and FALLING events."""
GPIO.add_event_detect(port, GPIO.BOTH, callback=event_callback, bouncetime=bounce)
/config/custom_components/rpi_gpio3/binary_sensor.py
"""Support for binary sensor using RPi GPIO."""
import asyncio
import voluptuous as vol
from .. import rpi_gpio3
from homeassistant.components.binary_sensor import PLATFORM_SCHEMA, BinarySensorEntity
from homeassistant.const import DEVICE_DEFAULT_NAME
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.reload import setup_reload_service
from . import DOMAIN, PLATFORMS
CONF_BOUNCETIME = "bouncetime"
CONF_INVERT_LOGIC = "invert_logic"
CONF_PORTS = "ports"
CONF_PULL_MODE = "pull_mode"
DEFAULT_BOUNCETIME = 50
DEFAULT_INVERT_LOGIC = False
DEFAULT_PULL_MODE = "UP"
_SENSORS_SCHEMA = vol.Schema({cv.positive_int: cv.string})
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
vol.Required(CONF_PORTS): _SENSORS_SCHEMA,
vol.Optional(CONF_BOUNCETIME, default=DEFAULT_BOUNCETIME): cv.positive_int,
vol.Optional(CONF_INVERT_LOGIC, default=DEFAULT_INVERT_LOGIC): cv.boolean,
vol.Optional(CONF_PULL_MODE, default=DEFAULT_PULL_MODE): cv.string,
}
)
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Raspberry PI GPIO devices."""
setup_reload_service(hass, DOMAIN, PLATFORMS)
pull_mode = config.get(CONF_PULL_MODE)
bouncetime = config.get(CONF_BOUNCETIME)
invert_logic = config.get(CONF_INVERT_LOGIC)
binary_sensors = []
ports = config.get("ports")
for port_num, port_name in ports.items():
binary_sensors.append(
RPiGPIOBinarySensor(
port_name, port_num, pull_mode, bouncetime, invert_logic
)
)
add_entities(binary_sensors, True)
class RPiGPIOBinarySensor(BinarySensorEntity):
"""Represent a binary sensor that uses Raspberry Pi GPIO."""
async def async_read_gpio(self):
"""Read state from GPIO."""
await asyncio.sleep(float(self._bouncetime) / 1000)
self._state = await self.hass.async_add_executor_job(
rpi_gpio3.read_input, self._port
)
self.async_write_ha_state()
def __init__(self, name, port, pull_mode, bouncetime, invert_logic):
"""Initialize the RPi binary sensor."""
self._name = name or DEVICE_DEFAULT_NAME
self._port = port
self._pull_mode = pull_mode
self._bouncetime = bouncetime
self._invert_logic = invert_logic
self._state = None
rpi_gpio3.setup_input(self._port, self._pull_mode)
def edge_detected(port):
"""Edge detection handler."""
self.hass.add_job(self.async_read_gpio)
rpi_gpio3.edge_detect(self._port, edge_detected, self._bouncetime)
@property
def should_poll(self):
"""No polling needed."""
return False
@property
def name(self):
"""Return the name of the sensor."""
return self._name
@property
def is_on(self):
"""Return the state of the entity."""
return self._state != self._invert_logic
def update(self):
"""Update the GPIO state."""
self._state = rpi_gpio3.read_input(self._port)
/config/custom_components/rpi_gpio3/services.yaml
reload:
description: Reload all rpi_gpio entities.
hi f-mosquera, thanks for testing. The error you got seems to be related to timing on startup: the hass object seems not to be initialized. I think it is related to the use as a custom component. If you want to test it as it will be if integrated you have to find the homeassistant/components/rpi_gpio/binary_sensor.py file on your system and replace it (temporaly) by the one out of the PR. The path were out can find it depends on your instalation and used python version. to find the file a command like: find / -name "binary_sensor.py" | grep "/rpi_gpio/" can help
Raspberry Pi 4 running hassos. The rio_gpio2 zip solution fixed my problem!
That needs to be moved into the production code!
hi f-mosquera, thanks for testing. The error you got seems to be related to timing on startup: the hass object seems not to be initialized. I think it is related to the use as a custom component. If you want to test it as it will be if integrated you have to find the homeassistant/components/rpi_gpio/binary_sensor.py file on your system and replace it (temporaly) by the one out of the PR. The path were out can find it depends on your instalation and used python version. to find the file a command like: find / -name "binary_sensor.py" | grep "/rpi_gpio/" can help
Thanks mburget, I tried your suggestion but as I'm running hassos those files don't show up. If there is an easy way to change that file in hassos or load a full version that contains it I can give it a try. Or if somebody has direct access to the components please test. I have been running for days the rpi_gpio3 setup as explained above, with the code that has been proposed for merge (without threading), and besides the glitch with the custom component at startup I can confirm that sensor states are detected correctly, as with the rpi_gpio2 solution.
hi f-mosquera, yes my proposed testing is not possible on hassos. I'm testing it in a python virtual environment where this files are accessible. Thanks for your effort
Make sure you are running the latest version of Home Assistant before reporting an issue.
Home Assistant release (
hass --version
): 0.57.2Python release (
python3 --version
): Python 3.5.3Component/platform: Binary Sensor GPIO on Raspberry Pi ( binary_sensor rpi_gpio)
Description of problem: The sensor does not trigger with very short connections. This sadly is the default case for the "Doorbell" Scenario. A self-made python script works as expected. Within hass, the first activation is always ignored. Afterwards, approximately 1/3 are not registered. An automation is not needed to reproduce.
Expected: Even a short hit on a button should trigger the binary sensor 100% of the time - hass.io should behave identically to manually implemented python scripts in that regard.
Problem-relevant
configuration.yaml
entries and steps to reproduce:Python that is working fine with the same hardware-setup can be found here: https://github.com/bahmrockk/homeassistantConfig/blob/master/doorbell.py
Additional info: I have tried a lot of different configurations, playing around with bouncetimes, inverted logic, etc etc. I'm now at a 80% confidence level that this is indeed a bug and not me being stupid :)