esphome / issues

Issue Tracker for ESPHome
https://esphome.io/
290 stars 36 forks source link

pcf8574 dont update state on input change #667

Closed maxx-ukoo closed 4 years ago

maxx-ukoo commented 5 years ago

Operating environment/Installation (Hass.io/Docker/pip/etc.):

Custom ESP32 board with i2C PCF8575 module

Affected component: https://esphome.io/components/pcf8574.html

Description of problem: i have 2 buttons - one directly attached to ESP32 io, second to PCF8575 expander. I able to see state update in logs for gpio attached button, but not for PCF8575 attached

Problem-relevant YAML-configuration entries:

binary_sensor:
  - platform: gpio
    pin:
      number: 4
      mode: INPUT
    name: "D4 input pin "
  - platform: gpio
    name: "PCF8575 Pin #7"
    pin: 
      pcf8574: pcf8575_hub
      number: 7
      # One of INPUT, INPUT_PULLUP or OUTPUT
      mode: INPUT
      inverted: false

Logs (if applicable):

[C][mqtt:060]:   Topic Prefix: 'etheresp32_pcf8575'
[C][mqtt:062]:   Log Topic: 'etheresp32_pcf8575/debug'
[C][mqtt:065]:   Availability: 'etheresp32_pcf8575/status'
[C][mqtt.switch:038]: MQTT Switch 'PCF8575 Pin #4':
[C][mqtt.switch:039]:   State Topic: 'etheresp32_pcf8575/switch/pcf8575_pin_4/state'
[C][mqtt.switch:039]:   Command Topic: 'etheresp32_pcf8575/switch/pcf8575_pin_4/command'
[C][mqtt.switch:038]: MQTT Switch 'PCF8575 Pin #5':
[C][mqtt.switch:039]:   State Topic: 'etheresp32_pcf8575/switch/pcf8575_pin_5/state'
[C][mqtt.switch:039]:   Command Topic: 'etheresp32_pcf8575/switch/pcf8575_pin_5/command'
[C][mqtt.switch:038]: MQTT Switch 'PCF8575 Pin #6':
[C][mqtt.switch:039]:   State Topic: 'etheresp32_pcf8575/switch/pcf8575_pin_6/state'
[C][mqtt.switch:039]:   Command Topic: 'etheresp32_pcf8575/switch/pcf8575_pin_6/command'
[C][mqtt.switch:038]: MQTT Switch 'PCF8575 Pin #7':
[C][mqtt.switch:039]:   State Topic: 'etheresp32_pcf8575/switch/pcf8575_pin_7/state'
[C][mqtt.switch:039]:   Command Topic: 'etheresp32_pcf8575/switch/pcf8575_pin_7/command'
[C][mqtt.binary_sensor:018]: MQTT Binary Sensor 'D4 input pin ':
[C][mqtt.binary_sensor:019]:   State Topic: 'etheresp32_pcf8575/binary_sensor/d4_input_pin_/state'
[C][mqtt.binary_sensor:018]: MQTT Binary Sensor 'PCF8575 Pin #7':
[C][mqtt.binary_sensor:019]:   State Topic: 'etheresp32_pcf8575/binary_sensor/pcf8575_pin_7/state'
[C][mqtt.binary_sensor:018]: MQTT Binary Sensor 'PCF8575 Pin #8':
[C][mqtt.binary_sensor:019]:   State Topic: 'etheresp32_pcf8575/binary_sensor/pcf8575_pin_8/state'
[C][mqtt.binary_sensor:018]: MQTT Binary Sensor 'PCF8575 Pin #9':
[C][mqtt.binary_sensor:019]:   State Topic: 'etheresp32_pcf8575/binary_sensor/pcf8575_pin_9/state'
[C][mqtt.binary_sensor:018]: MQTT Binary Sensor 'PCF8575 Pin #10':
[C][mqtt.binary_sensor:019]:   State Topic: 'etheresp32_pcf8575/binary_sensor/pcf8575_pin_10/state'
[D][binary_sensor:036]: 'D4 input pin ': Sending state OFF
[D][binary_sensor:036]: 'D4 input pin ': Sending state ON
[D][binary_sensor:036]: 'D4 input pin ': Sending state OFF
[D][binary_sensor:036]: 'D4 input pin ': Sending state ON
[D][binary_sensor:036]: 'D4 input pin ': Sending state OFF
[D][binary_sensor:036]: 'D4 input pin ': Sending state ON
[D][binary_sensor:036]: 'D4 input pin ': Sending state OFF

Additional information and things you've tried:

glmnet commented 5 years ago

did you try INPUT_PULLUP ?

S-Przybylski commented 5 years ago

Dear @glmnet dear @maxx-ukoo today i ran into an similar issue: I use the PCF8574 in input mode with external resistors 4k7 mounted. The configuration setting i use was 'mode: INPUT' for all 8 ports (non inverse). If you wire one of the input channels of the PCF8574 to ground (gnd) and power on the board (incl. the esp8266) then the input is fixed to gnd even if you cut the wire later on! You will also get no update in case of high/low voltage changes. That means the port seams to be "disabled".

If the port is not connected (but pulled up by default using external resistors) and the circuit is powered on, everythink works as expected! The port then reflects every change...

Then i tried to use the INPUT_PULLUP mode: Now everything works as expected even if there are two pullups now in parallel...

If in INPUT mode: Could it be that the port is set to outputmode when connected to ground instead of presenting an input port?

OttoWinter commented 5 years ago

Looks like a duplicate of https://github.com/esphome/issues/issues/460 - can someone confirm?

amishv commented 5 years ago

@S-Przybylski,

Can you please provide the voltage on the *INT pin (pin 13 in N package, pin 1 on other packages) for both the cases? This looks like an uncleared interrupt problem. The same could be true for #460 As per the datasheet:

The PCF8574A device provides an open-drain output (INT) that can be connected to the interrupt input of a microcontroller. An interrupt is generated by any rising or falling edge of the port inputs in the input mode. After time, t iv , INT is valid. Resetting and reactivating the interrupt circuit is achieved when data on the port is changed to the original setting or data is read from, or written to, the port that generated the interrupt.

amishv commented 5 years ago

@S-Przybylski, Also, please quote the wifi signal strength Signal strength: -68 dB ▂▄▆█

S-Przybylski commented 5 years ago

Dear @amishv my signal strength is -68 dB. After some minutes the logs shows values around -64 dB ... 'WiFi_signal_central': Sending state -64.00000 dB with 0 decimals of accuracy

I currently use interfaces of a german producer (horter), which also be able to forward the INT (inverse) to a individual GPIO and displays the status of each input, the I2C bus (high/low) and also of the INT using LEDs. Yes i can try to measure the voltage, but i just tried a easy method instead. Here are my testcase result using the LED, if i power on the ESP8266 with the PCF8574 board: Prerequisites:

Test 1. Initial situation: no input is wird to ground Observation: The interrupt LED does not light up; all port are working as excepted after boot. The LEDs on the input lines are off (inverted). Each time of a voltage change on any input leads to a flicker of the interrupt LED and the selected input LED reflects the correct input value.

Test 2. Initial situation: Port with input configuration (no internal pullup) is wired to ground Observation: The interrupt LED does light up for a short time. Any later voltage change on this input is not reflected by the interrupt line (no flicker) and! also not reflected by this input LED! It stays on (indicates a gnd level). All other are working as excepted (tested after boot).

Test 3. Initial situation: Port with input pull_up configuration (in parallel with fixed pullup) is wired to ground Observation: The interrupt LED does light up for a short time. Any later voltage change on the input side is reflected by the interrupt line (short flicker) and also reflected by the selected input LED: light is on for gnd and off for vcc.

S-Przybylski commented 5 years ago

One notice the the boards: I have connected the same interfaces (boards) directly to a Raspi3b: Here the Node-Red-implementation works a designed (but is not stable -> thats the reason why i want to move to esphome)... All ports are working, independently if the input is set to gnd or vcc at startup.

maxx-ukoo commented 5 years ago

@S-Przybylski, Can you please provide the voltage on the *INT pin (pin 13 in N package, pin 1 on other packages) for both the cases? This looks like an uncleared interrupt problem. The same could be true for #460 As per the datasheet: The PCF8574A device provides an open-drain output (INT) that can be connected to the interrupt input of a microcontroller. An interrupt is generated by any rising or falling edge of the port inputs in the input mode. After time, t iv , INT is valid. Resetting and reactivating the interrupt circuit is achieved when data on the port is changed to the original setting or data is read from, or written to, the port that generated the interrupt.

How i should connect interupt pin from PCF857X to esp? I didn't find anything about this interupt in documentation - https://esphome.io/components/pcf8574.html On start i see correct pin state, but for update state we need check state on interupt level. Does esphome do this?

S-Przybylski commented 5 years ago

Dear @maxx-ukoo Extender like PCF8574 or MCP23008/17 do have the abillity to either wire the interrupt directly to one GPIO or be used by software polling only instead. As i understand the esp8266 implementation, here is polling in use. That means, that the interrupt is reset by software polling.

In my node-red project on a raspi i definitly use the interrupt line to get a sign if a input changes.... This saves cpu power...

Your question regarding the voltage: I can try to do that later

For me it seems to be a software initialisation issue

OttoWinter commented 5 years ago

As i understand the esp8266 implementation, here is polling in use.

Correct, it is polling.

In my node-red project on a raspi i definitly use the interrupt line to get a sign if a input changes.... This saves cpu power...

Well these are very low-power devices anyway and reading i2c data does not take up a lot of time - the WiFi modem on the other hand uses way more power. Plus you have to connect one pin less.

amishv commented 5 years ago

@maxx-ukoo ,

I asked for the *INT pin voltage only to be sure that the chip is functioning normally and the interrupt is getting cleared after every I/O operation. I was looking for the pulse train on INT pin.

I have set up a new node (all my present node are online) today to reproduce this issue over the weekend.

amishv commented 5 years ago

@maxx-ukoo ,

I asked for the *INT pin voltage only to be sure that the chip is functioning normally and the interrupt is getting cleared after every I/O operation. I was looking for the pulse train on INT pin.

I have set up a new node here are the test results. All inputs (without pull-up) were tied to ground at startup.

There is no anomaly observed.

Configuration file

esphome: name: testboard platform: ESP8266 board: nodemcuv2

Enable logging

logger:

i2c: sda: D2 scl: D1 scan: False

pcf8574:

binary_sensor:

S-Przybylski commented 5 years ago

Dear @amishv for me it seems that your configuration always uses input_pullup instead of input only.

The testcase will be:

  1. wire a selected pin (e.g. pin 4?) with a resistor (4k7) to vcc
  2. wire the same pin temporarily to gnd
  3. power on the esp8266 and the pcf8574 device
  4. after the esp booted: cut or disable the connection to gnd (leave the resistor to vcc present) and check: a.) the voltage on the pin (it should be vcc) b.) the voltage on the int (it should be vcc) because its inverted - i expect no change here, if you run into the same error i do c.) the log of the ESP

I am realy interrested if you get the same results i have!

amishv commented 5 years ago

@S-Przybylski ,

I can confirm now, input_pullup does not reproduce this issue. here is the log. I already had a problem with 8754 as it is Quasi bidirectional bus it does not need setting like input_pullup .

[22:16:11][C][i2c:028]: I2C Bus: [22:16:11][C][i2c:029]: SDA Pin: GPIO4 [22:16:11][C][i2c:030]: SCL Pin: GPIO5 [22:16:11][C][i2c:031]: Frequency: 50000 Hz

[22:16:11][C][pcf8574:022]: Address: 0x20 [22:16:11][C][pcf8574:023]: Is PCF8575: NO [22:16:11][C][gpio.binary_sensor:015]: GPIO Binary Sensor 'Switch1' [22:16:11][C][gpio.binary_sensor:015]: Device Class: 'light' [22:16:11][C][gpio.binary_sensor:016]: Pin: GPIO4 (Mode: INPUT) [22:16:11][C][gpio.binary_sensor:015]: GPIO Binary Sensor 'Switch2' [22:16:11][C][gpio.binary_sensor:015]: Device Class: 'light' [22:16:11][C][gpio.binary_sensor:016]: Pin: GPIO5 (Mode: INPUT) [22:16:11][C][gpio.binary_sensor:015]: GPIO Binary Sensor 'Switch3' [22:16:11][C][gpio.binary_sensor:015]: Device Class: 'light' [22:16:11][C][gpio.binary_sensor:016]: Pin: GPIO6 (Mode: INPUT) [22:16:11][C][gpio.binary_sensor:015]: GPIO Binary Sensor 'Switch4' [22:16:11][C][gpio.binary_sensor:016]: Pin: GPIO7 (Mode: INPUT)

[22:16:11][C][logger:138]: Level: DEBUG [22:16:11][C][logger:139]: Log Baud Rate: 115200 [22:16:11][C][logger:140]: Hardware UART: UART0

Maybe, we need to check Aurdino Library for 8574???

amishv commented 5 years ago

I was able to correct this by removing redundant code from PCF8574Component::pin_mode The datasheet say it is a Quasi bidirectional port and does not support pullup.

void PCF8574Component::pin_mode(uint8_t pin, uint8_t mode) { switch (mode) { case PCF8574_OUTPUT: this->ddrmask |= (1 << pin); this->portmask &= ~(1 << pin); break; default: this->ddrmask &= ~(1 << pin); this->portmask |= (1 << pin); break; }


Below are the logs.

[15:20:04][I][app:028]: Running through setup()... [15:20:04][C][pcf8574:010]: Setting up PCF8574... [15:20:04][D][binary_sensor:033]: 'Switch1': Sending state ON [15:20:04][I][app:060]: setup() finished successfully! [15:20:04][I][app:096]: esphome version 1.13.6 compiled on Oct 19 2019, 15:19:09 [15:20:04][C][i2c:028]: I2C Bus: [15:20:04][C][i2c:029]: SDA Pin: GPIO4 [15:20:04][C][i2c:030]: SCL Pin: GPIO5 [15:20:04][C][i2c:031]: Frequency: 50000 Hz

[15:20:04][C][pcf8574:022]: Address: 0x20 [15:20:04][C][pcf8574:023]: Is PCF8575: NO [15:20:04][C][gpio.binary_sensor:015]: GPIO Binary Sensor 'Switch1' [15:20:04][C][gpio.binary_sensor:016]: Pin: GPIO4 (Mode: INPUT)

[15:20:04][C][logger:138]: Level: DEBUG [15:20:04][C][logger:139]: Log Baud Rate: 115200 [15:20:04][C][logger:140]: Hardware UART: UART0 [15:20:10][D][binary_sensor:033]: 'Switch1': Sending state OFF [15:20:11][D][binary_sensor:033]: 'Switch1': Sending state ON [15:20:11][D][main:092]: The state of sw 1 is 1 [15:20:13][D][binary_sensor:033]: 'Switch1': Sending state OFF [15:20:13][D][binary_sensor:033]: 'Switch1': Sending state ON [15:20:13][D][main:092]: The state of sw 1 is 1 [15:20:20][D][binary_sensor:033]: 'Switch1': Sending state OFF


[15:20:23]logger:116]: Log initialized [15:20:23][I][app:028]: Running through setup()... [15:20:23][C][pcf8574:010]: Setting up PCF8574... [15:20:23][D][binary_sensor:033]: 'Switch1': Sending state OFF [15:20:23][I][app:060]: setup() finished successfully! [15:20:23][I][app:096]: esphome version 1.13.6 compiled on Oct 19 2019, 15:19:09 [15:20:23][C][i2c:028]: I2C Bus: [15:20:23][C][i2c:029]: SDA Pin: GPIO4 [15:20:23][C][i2c:030]: SCL Pin: GPIO5 [15:20:23][C][i2c:031]: Frequency: 50000 Hz

[15:20:23][C][pcf8574:022]: Address: 0x20 [15:20:23][C][pcf8574:023]: Is PCF8575: NO [15:20:23][C][gpio.binary_sensor:015]: GPIO Binary Sensor 'Switch1' [15:20:23][C][gpio.binary_sensor:016]: Pin: GPIO4 (Mode: INPUT)

[15:20:23][C][logger:138]: Level: DEBUG [15:20:23][C][logger:139]: Log Baud Rate: 115200 [15:20:23][C][logger:140]: Hardware UART: UART0 [15:20:26][D][binary_sensor:033]: 'Switch1': Sending state ON [15:20:26][D][main:092]: The state of sw 1 is 1 [15:20:26][D][binary_sensor:033]: 'Switch1': Sending state OFF [15:20:26][D][binary_sensor:033]: 'Switch1': Sending state ON [15:20:26][D][main:092]: The state of sw 1 is 1

S-Przybylski commented 5 years ago

Dear @amishv i am a little bit confused by now. I just reviewed the specs of the pcf8574 (ti). Could you check/confirm?

  1. I do not find any hint, that input_pullup (for me this is a mode where the input pin is connected to vcc using a internal resistor) can be set up. This is for me quite ok, because my boards have external resistors to vcc installed. Is input_pullup a valid mode at all?
  2. Why does input do not function if a input is wired to gnd, but input_pullup does? Does your change fix this?
  3. Do you provide a pull request for the change?
  4. Why do you use the name switch for binary_sensors? I expect binary_sensors instead
amishv commented 5 years ago

@S-Przybylski , Thanks for the bulleted points, this was precisely my point.

I do not find any hint, that input_pullup (for me this is a mode where the input pin is connected to vcc using a internal resistor) can be set up. This is for me quite ok, because my boards have external resistors to vcc installed. Is input_pullup a valid mode at all?

There are no configurable resistors in PCF8574 comparable to AVR. It is a quasi bidirectional pins (port, if you please).

Why does input do not function if a input is wired to gnd, but input_pullup does? Does your change fix this?

Yes, there are further routine in aurdino library which depend on DDR and PORT which are relevant to AVR. we need to set them correctly as we are emulating AVR in Esphome.

Do you provide a pull request for the change?

I have already pasted the solution, I am having issues with github as there were multiple updates today. However if you can test by modifying the lcd_display.cpp & lcd_display.h in the directory

/home//.local/lib/python/site-packages/esphome/components/lcd_base that will be of a great help.

Why do you use the name switch for binary_sensors? I expect binary_sensors instead

I guess, that is how In wanted to distinguish with the switches that they were handling like

`binary_sensor:

Hope that helped.

OttoWinter commented 5 years ago

Oh, do I understand correctly that the PCF8574 doesn't really support input pullup?

amishv commented 5 years ago

Oh, do I understand correctly that the PCF8574 doesn't really support input pullup?

Yes Please.

The device features an 8-bit quasi-bidirectional I/O port (P0–P7), including latched outputs with high-current drive capability for directly driving LEDs. Each quasi-bidirectional I/O can be used as an input or output without the use of a data-direction control signal.

amishv commented 5 years ago

Submitted pull request https://github.com/esphome/esphome/pull/782

S-Przybylski commented 5 years ago

Dear @OttoWinter what i find out was (hoppfully this is right), that the initalization need to configure all input and output ports. All ports which are not defined should be set to output port by default. And yes i don't see any internal pullup (vcc) resitors in place - referring scheme page 12: http://www.ti.com/lit/ds/symlink/pcf8574.pdf

My investigation regarding the current implementation: Input_pullup works while input not.

S-Przybylski commented 4 years ago

Dear @OttoWinter could we adapt the setting for input in the same way input_pullup works as a workaround until the module is revised? Then the module works from input side as expected!

Today i have successfully tested this little change in pcf8574.cpp: this->portmask &= ~(1 << pin); --> this->portmask |= (1 << pin);

void PCF8574Component::pin_mode(uint8_t pin, uint8_t mode) {
  switch (mode) {
    case PCF8574_INPUT:
      this->ddr_mask_ &= ~(1 << pin);
//      this->port_mask_ &= ~(1 << pin);
      this->port_mask_ |= (1 << pin);
      break;
    case PCF8574_INPUT_PULLUP:
      this->ddr_mask_ &= ~(1 << pin);
      this->port_mask_ |= (1 << pin);
      break;
    case PCF8574_OUTPUT:
      this->ddr_mask_ |= (1 << pin);
      this->port_mask_ &= ~(1 << pin);
      break;
    default:
      break;
  }