Skip to content

Commit

Permalink
split code for cover from switch and sensor, rewrote part of sensor i…
Browse files Browse the repository at this point in the history
…nitialization, and added debounce for cover state
  • Loading branch information
jdeneef committed Nov 2, 2024
1 parent 2ba85bc commit f441d5b
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 35 deletions.
2 changes: 1 addition & 1 deletion README-DEV.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,5 @@ xdg-open /tmp/mmark.html
To generate changelog with commit message use `git lt`, which is:

```bash
git log --graph --abbrev-commit --decorate --format=format:'%C(green)(%as)%C(reset) %C(yellow)%D%n%C(bold cyan)%s%C(reset)' --all
git log --graph --abbrev-commit --decorate --format=format:'%C(green)(%as)%C(reset) %C(yellow)%D%n%C(bold cyan)<%s%C(reset)' --all
```
30 changes: 12 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

This HACS integration is used to address GPIO (especially and only tested for RaspberryPi) using libgpiod and python gpiod >=v2.02 since RPI.gpio is no longer supported. I created this for my own use, and to understand a custom integration, but since it is working on Raspberry pi feel free to use.

**This work is copied over to the original HACS [RPI_GPIO](https://github.com/thecode/ha-rpi_gpio) integration. You should most likely check the that integration instead of this one. I'm keeping this repository for my own fun and use for now.**

**This is working in my homeassistant environment, that's it. Shared for testing and usage at your own risk!**

`ha_gpiod` is based on [ha-rpi_gpio](https://github.com/thecode/ha-rpi_gpio), which was already adapted for `gpiod` in [ha-gpio](https://codeberg.org/raboof/ha-gpio) and rewritten from scratch by me ..
Expand Down Expand Up @@ -84,10 +86,8 @@ Key | Required | Default | Type | Description
`port` | yes | | integer | the GPIO port to be used
`unique_id` | no | generated | string | An ID that uniquely identifies the sensor. Set this to a unique value to allow customization through the UI, auto generated when not set manually in config
`debounce` | no | `50` | integer | The time in milliseconds for port debouncing
`active_low` | no | `false` | boolean | If `true`, input of `gpio` is inverted, `active_low` results in `on`
`invert_logic` | *backwards compatibility* | | boolean | see `active_low`, might be removed in the future
`bias` | no | `PULL_UP` | string | control bias setting of GPIO, used to define the electrical state of a GPIO line when not actively driven; `PULL_UP` set weak pull-up resistor on the line, ensuring that the line is pulled to a high level (3.3V or 5V) when not actively driven; `PULL_DOWN` sets weak pull-down resistor to pull to low level (0V), `DISABLED` remains floating, `AS_IS` not changed
`pull_mode` | *backwards compatibility* | | string | see `bias`, might be removed in the future
`active_low` or `invert_logic` | no | `false` | boolean | If `true`, input of `gpio` is inverted, `active_low` results in `on`; `invert_logic` kept for backwards compatibility
`bias` or `pull_mode` | no | `PULL_UP` | string | control bias setting of GPIO, used to define the electrical state of a GPIO line when not actively driven; `PULL_UP` set weak pull-up resistor on the line, ensuring that the line is pulled to a high level (3.3V or 5V) when not actively driven; `PULL_DOWN` sets weak pull-down resistor to pull to low level (0V), `DISABLED` remains floating, `AS_IS` not changed; `pull_mode` kept for backwards compatibility


## Switch
Expand All @@ -103,10 +103,8 @@ Key | Required | Default | Type | Description
`name` | yes | | string | The name for the switch entity
`port` | yes | | integer | the GPIO port to be used
`unique_id` | no | generated | string | An ID that uniquely identifies the switch. Set this to a unique value to allow customization through the UI, auto generated when not set manually in config
`active_low` | no | `false` | boolean | If `true`, output of `gpio` is inverted, `active_low` switches `on`
`invert_logic` | *backwards compatibility* | | boolean | see `active_low`, might be removed in the future
`bias` | no | `AS_IS` | string | Type of internal pull resistor to use: `PULL_UP` - pull-up resistor, `PULL_DOWN` - pull-down resistor, `AS-IS` no change
`pull_mode`|*backwards compatibility*| |string|see `bias`, might be removed in the future
`active_low` or `invert_logic`| no | `false` | boolean | If `true`, output of `gpio` is inverted, `active_low` switches `on`; `invert_logic` kept for backwards compatibility
`bias` or `pull_mode` | no | `AS_IS` | string | Type of internal pull resistor to use: `PULL_UP` - pull-up resistor, `PULL_DOWN` - pull-down resistor, `AS-IS` no change; `pull_mode` kept for backwards compatibility
`drive`|no| `PUSH_PULL`|string | control drive configuration of the GPIO, determines how the line behaves when it is set to output mode; `PUSH_PULL`, GPIO line can both source and sink current, can actively drive the line to both high and low states. `OPEN-DRAIN`, GPPIO can only sink current (drive the line to low) and is otherwise left floating, and `OPEN-SOURCE` the reverse.
`persistent` | no | `false` | boolean | If true, the switch state will be persistent in HA and will be restored if HA restart / crash.

Expand All @@ -120,19 +118,15 @@ Covers consist of a switch for triggering cover motor, and a state sensor for de
Key | Required | Default | Type | Description
--- | --- | --- | --- | ---
`name` | yes | | string | The name for the cover entity
`relay_port`|yes| |integer|Relay switch gpio switching cover motor
`relay_pin`|*backwards compatibility*| |integer|see `relay_port`, might be removed in the future
`relay_port` or `relay_pin`|yes| |integer|Relay switch gpio switching cover motor; `relay_pin` kept for backwards compatibility
`relay_time`|no|`200` |integer|Time in milliseconds relay switch will be switched to open/close cover
`relay_active_low`|no | `false`| boolean| invert input for `relay_port`
`invert_relay`|*backwards compatibility*| | boolean|see `relay_active_low`, might be removed in the future
`relay_active_low` or `invert_relay`|no | `false`| boolean| invert input for `relay_port`; `invert_relay` kept for backwards compatibility
`relay_bias` | no | `AS_IS` | string | Type of internal pull resistor to use: `PULL_UP` - pull-up resistor, `PULL_DOWN` - pull-down resistor
`relay_drive`|no|`PUSH_PULL`|string|set `relay_pin` `drive_mode`, options: `OPEN_DRAIN`, `OPEN_SOURCE`, `PUSH_PULL`
`state_port`|yes| | integer|State port for opened/closed status of cover
`state_pin`|*backwards compatibility*| | integer|see `state_port`, might be removed in the future
`state_bias` | no | `PULL_UP` | string | Type of internal pull resistor to use: `PULL_UP` - pull-up resistor, `PULL_DOWN` - pull-down resistor
`state_pull_mode`|*backwards compatibility*| |string|see `state_bias`, might be removed in the future
`state_active_low`|no | `false`| boolean| invert output for state pin
`invert_state`|*backwards compatibility*| |boolean|see `state_active_low`, might be removed in the future
`state_port` or `state_pin`|yes| | integer|State port for opened/closed status of cover; `state_pin` kept for backwards compatibility
`state_bias` or `state_pull_mode`| no | `PULL_UP` | string | Type of internal pull resistor to use: `PULL_UP` - pull-up resistor, `PULL_DOWN` - pull-down resistor; `state_pull_mode` kept for backwards compatibility
`state_active_low` or `invert_state`|no | `false`| boolean| invert output for state pin; `invert_state` kept for backwards compatibility
`state_debounce`|no | 50 | integer | debounce parameter for the cover state sensor
`unique_id` | no | generated | string | An ID that uniquely identifies the switch. Set this to a unique value to allow customization through the UI, auto generated when not set manually in config


Expand Down
14 changes: 8 additions & 6 deletions custom_components/gpiod/cover.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
DEFAULT_STATE_BIAS = "PULL_UP"
CONF_STATE_ACTIVE_LOW = "state_active_low"
DEFAULT_STATE_ACTIVE_LOW = False
CONF_STATE_DEBOUNCE = "state_debounce"
DEFAULT_STATE_DEBOUNCE = 50

import homeassistant.helpers.config_validation as cv
import voluptuous as vol
Expand All @@ -48,6 +50,7 @@
vol.Required(vol.Any(CONF_STATE_PORT,"state_pin")): cv.positive_int,
vol.Optional(vol.Any(CONF_STATE_BIAS, "state_pull_mode")): vol.In(BIAS.keys()),
vol.Optional(vol.Any(CONF_STATE_ACTIVE_LOW, "invert_state")): cv.boolean,
vol.Optional(CONF_STATE_DEBOUNCE, default=DEFAULT_STATE_DEBOUNCE): cv.positive_int,
vol.Optional(CONF_UNIQUE_ID): cv.string,
}]
)
Expand Down Expand Up @@ -81,6 +84,7 @@ async def async_setup_platform(
cover.get(CONF_STATE_PORT) or cover.get("state_pin"),
cover.get(CONF_STATE_BIAS) or cover.get("state_bias") or DEFAULT_STATE_BIAS,
cover.get(CONF_STATE_ACTIVE_LOW) or cover.get("invert_state") or DEFAULT_STATE_ACTIVE_LOW,
cover.get(CONF_STATE_DEBOUNCE),
cover.get(CONF_UNIQUE_ID) or f"{DOMAIN}_{cover.get(CONF_RELAY_PORT) or cover.get("relay_pin")}_{cover[CONF_NAME].lower().replace(' ', '_')}",
)
)
Expand All @@ -91,7 +95,7 @@ class GPIODCover(CoverEntity):
should_poll = False

def __init__(self, hub, name, relay_port, relay_time, relay_active_low, relay_bias, relay_drive,
state_port, state_bias, state_active_low, unique_id):
state_port, state_bias, state_active_low, state_debounce, unique_id):
_LOGGER.debug(f"GPIODCover init: {relay_port}:{state_port} - {name} - {unique_id} - {relay_time}")
self._hub = hub
self.name = name
Expand All @@ -103,19 +107,17 @@ def __init__(self, hub, name, relay_port, relay_time, relay_active_low, relay_bi
self._state_port = state_port
self._state_bias = state_bias
self._state_active_low = state_active_low
self._state_debounce = state_debounce
self.unique_id = unique_id
self._attr_is_closed = False != state_active_low

async def async_added_to_hass(self) -> None:
await super().async_added_to_hass()
self._hub.add_cover(self, self._relay_port, self._relay_active_low, self._relay_bias,
self._relay_drive, self._state_port, self._state_bias, self._state_active_low)
self._relay_drive, self._state_port, self._state_bias,
self._state_active_low, self._state_debounce)
self.async_write_ha_state()

# dirty hack to enable reuse of switch
def is_on(self):
return False

def update(self):
self.is_closed = self._hub.update(self._state_port)
self.schedule_update_ha_state(False)
Expand Down
53 changes: 43 additions & 10 deletions custom_components/gpiod/hub.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,12 +163,15 @@ def turn_off(self, port) -> None:

def add_sensor(self, entity, port, active_low, bias, debounce) -> None:
_LOGGER.debug(f"in add_sensor {port}")
# read current status of the sensor
line = self._chip.request_lines({ port: {} })
value = True if line.get_value(port) == Value.ACTIVE else False
entity.is_on = True if value ^ active_low else False
line = self._chip.request_lines({ port: gpiod.LineSettings(
direction = Direction.INPUT,
bias = BIAS[bias],
active_low = active_low
) })
line_value = line.get_value(port)
entity.is_on = True if line_value == Value.ACTIVE else False
line.release()
_LOGGER.debug(f"current value for port {port}: {entity.is_on}")
_LOGGER.debug(f"current value for port {port}: {line_value}")

self._entities[port] = entity
self._config[port] = gpiod.LineSettings(
Expand All @@ -178,17 +181,47 @@ def add_sensor(self, entity, port, active_low, bias, debounce) -> None:
active_low = active_low,
debounce_period = timedelta(milliseconds=debounce),
event_clock = Clock.REALTIME,
output_value = Value.ACTIVE if entity.is_on else Value.INACTIVE,
output_value = line_value
)
self._edge_events = True

def update(self, port, **kwargs):
return self._lines.get_value(port) == Value.ACTIVE

def add_cover(self, entity, relay_port, relay_active_low, relay_bias, relay_drive,
state_port, state_bias, state_active_low) -> None:
state_port, state_bias, state_active_low, state_debounce) -> None:
_LOGGER.debug(f"in add_cover {relay_port} {state_port}")
self.add_switch(entity, relay_port, relay_active_low, relay_bias, relay_drive)
self.add_sensor(entity, state_port, state_active_low, state_bias, 50)
self.update_lines()

# add switch
self._entities[relay_port] = entity
self._config[relay_port] = gpiod.LineSettings(
direction = Direction.OUTPUT,
bias = BIAS[relay_bias],
drive = DRIVE[relay_drive],
active_low = relay_active_low,
output_value = Value.INACTIVE
)

# add sensor
line = self._chip.request_lines({ state_port: gpiod.LineSettings(
direction = Direction.INPUT,
bias = BIAS[state_bias],
active_low = state_active_low
) })
line_value = line.get_value(state_port)
entity.is_closed = True if line_value == Value.ACTIVE else False
line.release()
_LOGGER.debug(f"current value for port {state_port}: {line_value}")

self._entities[state_port] = entity
self._config[state_port] = gpiod.LineSettings(
direction = Direction.INPUT,
edge_detection = Edge.BOTH,
bias = BIAS[state_bias],
active_low = state_active_low,
debounce_period = timedelta(milliseconds=state_debounce),
event_clock = Clock.REALTIME,
output_value = line_value
)
self._edge_events = True

0 comments on commit f441d5b

Please sign in to comment.