MCP23017 chip settings

Next steps in testing are positive. Connected PIR sensor which should turn on the lights in the hall. The challenge was that from sensing presence by PIR sensor, light should be turned on instantly. With previous integration, taking sometimes more than 1 second delay it did not work as person would be half way in the hall (or more) when the lights turned on.
With this integration the lights goes on practically instantly! So I am happy !
(Small note, that internal pull-up resistor either does not seem to work or is too small for my PIR sensor or maybe is not enabled ? Anyhow connecting external pull-up resistor does the work and all work fine.)

For interrupt and several chips I understand open drain. So the logic is that in case of interrupt RPi goes to all defined chips and all defined binary sensor to check the state and reflect in HA, correct ?
Based on MCP23017 documentation there is “INTF register, which reflects the interrupt condition on the port pins of any pin that is enabled for interrupts via the GPINTEN register. A ‘set’ bit indicates that the associated pin caused the interrupt.” But using this logic the software should first know which chip is it (than each chip should have it own interrupt connected to RPi) and then would read only the indicated input - this would be super optimal and fastest.

I am trying (with my limited programming knowledge) understand this logic in binary_sensor.py but need some time to do it. The challenge is probably also that some (or most) of the communication between chip and RPi is done in those Adafruit/Arduino components - and this is another step in my education/investigation. :slight_smile:

Yeah, the orriginal code (in a prevoius version) did do that. They had some issues reading the register from the chip and reverted to this method.

The owner is lookig for help to get that sorted. That is why i tried to modify the code to see what is does.
I got stuck at other issues and was put on the wrong track regarding the stabilty, glad that you used teh same code and all is working fine. I will first get my i2c bus to do what it should and then continue on the code.

Since the release of the component some major includes have been upgraded, so maybe it now works as intended. The original lines that use the scan are still in de binary_sensor.py.

There a 2 parts that sort of run side by side, the setup in python and the correlation of the sensors in HA. Then the int-gpio change detection that reads the chip and updates the corresponding sensors in HA.

It’s straight foreward code and with a bt of help from the docs of HA custom components i figured out how to read it and make some changes including the debug line in de HA log to see what the script is doing at what point in time.

If you need help with the code let me know.

OK.
Now not so good news… :frowning:
So far I had 1 input and 9 outputs defined. Few days ago I have added one more input and this created some problems observed on HA card:

  1. This new input (pulled up) did not respond properly - there was delay after connecting to ground.
  2. The state was not changed either way (after putting it on ground or putting high)
  3. I think that also my Outputs has been “toughed” and started to not work as they should.

It could potentially be that the line to this input was long (I mean cable) so putting it to ground could make still some voltage on the input. But I believe I have also done some test exactly on the chip so there was ground for sure and still behaviour was the same.
As I did not have much time to test (the connection I made was sort of emergency) I gave up and went other solution. At this point I have suspicion that more then 1 GPIO defined as input may create a problem for this integration ?
@Peerke - thank you for help in understanding the code, I hope end of this week or next one will have some time to contact you. Should we exchange info here or maybe more “privately”?

On top of interrup I also see a challenge with using “inverted” option for Input. It seems that current integration can only allow to do it for ALL inputs not per individual. When I look for MCP23017 integration with ESPHome it is done they was I would love to see it in HA on RPi, which woudl have possiblity to invert individual inputs and also define each whether it is internally pulled-up or pulled-down.

# Individual inputs
binary_sensor:
  - platform: gpio
    name: "MCP23017 Pin #1"
    pin:
      mcp23017: mcp23017_hub
      # Use pin number 1
      number: 1
      # One of INPUT or INPUT_PULLUP
      mode: INPUT_PULLUP
      inverted: False

Will work on it more as few days ago I got more MC23017 chips which I can do tests with - so also multiple chips on one IC2 line will be tested.

Hi @Maco65,

I sent you a PM.

Interesting find around the 1 input, my chip only serves inputs, i wil see what happens if i just enable 1 in the config of HA.
Also good test to see if i change the rest to output in HA.
Just to see where in the integration stuff breaks.

from the datasheet:
16-Bit Remote Bidirectional I/O Port:

  • I/O pins default to input

Kind regards,
Peter

I will comment the below info from another topic:

Your experience is strange. I have one chip connected to RPi4 since May 2020 and generally it works OK. There is a challenge with response time for binary sensors (discussed above) but other then that it is OK. However it happened 2-3 times during last month that I had to reboot HA server as the switches did not work. The other chip I have is connected to Esp8266 and configured only as switches - did not noticed any issues so far.

@bigu1975 - related to your input in another topic:

it is a very good point on retaining the values during restart and “reseting” the chip in case there is instability. Maybe your script can be added to local (or official) integration to help others ?
I wonder how this is made when MCP23017 is used on ESPHome or TASMOTA ? Particulary on Tasmota there seem to be more options…

To be more clear:
Now the reset of switch states of MCP23017 is doing HA during every restart - this is something, which I don’t like but I can survive :slight_smile:

The critical problem for me is fact that from time to time my switches or/and sensors are become unresponsive after HA restart.

And here is my magic :slight_smile:
Every HA restart I am calling external python “script” (script it is too much said) - few lines to make the init without resetting MCP states:

#!/usr/bin/env python
from IOPi import IOPi

bus = IOPi(0x20)
bus.set_port_direction(0, 0x00)
bus.set_port_direction(1, 0x00)

bus3 = IOPi(0x23)
bus3.set_port_direction(0, 0xFF)
bus3.set_port_pullups(0, 0xFF)
bus3.set_port_direction(1, 0xFF)
bus3.set_port_pullups(1, 0xFF)
bus3.set_interrupt_defaults(0, 0x00)
bus3.set_interrupt_defaults(1, 0x00)
bus3.set_interrupt_type(0, 0x00)
bus3.set_interrupt_type(1, 0x00)
bus3.set_interrupt_on_port(0, 0xFF)
bus3.set_interrupt_on_port(1, 0xFF)
bus3.reset_interrupts()

exit

The hugest added value of my “script” is fact that for sensors I do activate of Interrupts signals connected to RPI GPIO - so having simple automation I can check sensors only on real state change.

And final disclaimer - I am not a programmer, I know that my workaround is very ‘dirty’ solution but only in that way I can work with HA and MCP2017 quite stable.
And as I am not programmer I was not able to make this as Custom Addon so to be able to implement my script I have HA installed in docker.

Hope it helps

I edit this post with the latest results of the various tests.
My HA runs in Hassio in RP4. The MCP23017 integration always works well only with the pins set as inputs (binary_sensor) and therefore does not create any problems for me.
There are problems with the “switch” configuration. In fact, if I reset the chip with the appropriate pin, the functionality of the switches is lost: they do not respond to the command.
Furthermore, if I leave the outputs active, I often find them turned off without HA being, without a power failure or other. It seems that integration is unstable.
To reactivate the switches I must necessarily restart HA.
I ask you if this happens to you too and if you have any suggestions for this problem. I am currently porting the switches to esphome, which is much more stable and reliable, and I only use the integration for inputs. Thanks

I am sorry, but I cannot spare time for this topic at the moment…

is there some progress on this?
I’m using the “standard” integration but i have to restart HA multiple times per day
i have 2 chips: 1 input and 1 output

the error i get is the next:

2021-01-30 07:35:19 ERROR (MainThread) [homeassistant.components.websocket_api.http.connection] [2881418840] [Errno 121] Remote I/O error
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/components/websocket_api/commands.py", line 135, in handle_call_service
await hass.services.async_call(
File "/usr/src/homeassistant/homeassistant/core.py", line 1445, in async_call
task.result()
File "/usr/src/homeassistant/homeassistant/core.py", line 1480, in _execute_service
await handler.job.target(service_call)
File "/usr/src/homeassistant/homeassistant/helpers/entity_component.py", line 204, in handle_service
await self.hass.helpers.service.entity_service_call(
File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 593, in entity_service_call
future.result() # pop exception if have
File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 664, in async_request_call
await coro
File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 630, in _handle_entity_call
await result
File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 699, in async_turn_off
await self.hass.async_add_executor_job(ft.partial(self.turn_off, **kwargs))
File "/usr/local/lib/python3.8/concurrent/futures/thread.py", line 57, in run
result = self.fn(*self.args, **self.kwargs)
File "/usr/src/homeassistant/homeassistant/components/mcp23017/switch.py", line 89, in turn_off
self._pin.value = self._invert_logic
File "/usr/local/lib/python3.8/site-packages/adafruit_mcp230xx/digital_inout.py", line 94, in value
self._mcp.gpio = _enable_bit(self._mcp.gpio, self._pin)
File "/usr/local/lib/python3.8/site-packages/adafruit_mcp230xx/mcp23017.py", line 77, in gpio
return self._read_u16le(_MCP23017_GPIOA)
File "/usr/local/lib/python3.8/site-packages/adafruit_mcp230xx/mcp230xx.py", line 56, in _read_u16le
i2c.write_then_readinto(_BUFFER, _BUFFER, out_end=1, in_start=1, in_end=3)
File "/usr/local/lib/python3.8/site-packages/adafruit_bus_device/i2c_device.py", line 124, in write_then_readinto
self.i2c.writeto_then_readfrom(
File "/usr/local/lib/python3.8/site-packages/busio.py", line 133, in writeto_then_readfrom
return self._i2c.writeto_then_readfrom(
File "/usr/local/lib/python3.8/site-packages/adafruit_blinka/microcontroller/generic_linux/i2c.py", line 87, in writeto_then_readfrom
readin = self._i2c_bus.read_i2c_block_data(
File "/usr/local/lib/python3.8/site-packages/Adafruit_PureIO/smbus.py", line 273, in read_i2c_block_data
ioctl(self._device.fileno(), I2C_RDWR, request)
OSError: [Errno 121] Remote I/O error

Hi Niels,

Looks like your error is related to the I2C communication with the MCP’s

I stopped working on it and moved to Arduino as I was getting different behaviour all the time.
My setup now has an Arduino Mega with an ethernetShield, 2 MCP’s, 2 ADS1115 that do a publish to the MQTT broker in HA. All is working fine even the interrupt from the MCP is now working as it should.

From what I have seen in creating the Arduino code is that the MCP’s need specific read order to get the port status and that HA (python containers) are not friends with the I2C communications of the RaspberryPi. I do not have a development setup so for me troubleshooting is hard and time-consuming.