Skip to content

Expand the rpi_gpio component to support orangepi as well.#19732

Closed
mikalstill wants to merge 7 commits intohome-assistant:devfrom
mikalstill:rpi_gpio
Closed

Expand the rpi_gpio component to support orangepi as well.#19732
mikalstill wants to merge 7 commits intohome-assistant:devfrom
mikalstill:rpi_gpio

Conversation

@mikalstill
Copy link
Copy Markdown

@mikalstill mikalstill commented Jan 3, 2019

Description:

Instead of adding a new component for orangepi (which is a raspberry pi clone), let's just extend the existing component to support more than one family of boards.

I have tested this patch on a raspberry pi 3 and an orangepi prime, in both cases with a LED on a GPIO controlled switch. Note that the orangepi GPIO library requires access to /dev/mem, which I have resolved for now by running Home Assistant as root.

I'm holding off on a home-assistant.io pull request to match this until I get a feel for if this approach is acceptable to you.

This code was implemented to support a Home Assistant tutorial running at linux.conf.au 2019 in a couple of weeks, it would be super cool to be able to have this merged by then so that attendees don't need to carry private patches.

Example entry for configuration.yaml (if applicable):

rpi_gpio:
  board_family: orange_pi
  board: prime

switch:
 - platform: rpi_gpio
   ports:
     29: LED

Checklist:

  • The code change is tested and works locally.
  • Local tests pass with tox. Your PR cannot be merged unless tests pass
  • There is no commented out code in this PR.

If user exposed functionality or configuration variables are added/changed:

If the code communicates with devices, web services, or third-party tools:

  • New dependencies have been added to the REQUIREMENTS variable (example).
  • New dependencies are only imported inside functions that use them (example).
  • New or updated dependencies have been added to requirements_all.txt by running script/gen_requirements_all.py.
  • New files were added to .coveragerc.

If the code does not interact with devices:

  • Tests have been added to verify that the new code works.

@homeassistant
Copy link
Copy Markdown
Contributor

Hi @mikalstill,

It seems you haven't yet signed a CLA. Please do so here.

Once you do that we will be able to review and accept this pull request.

Thanks!

@mikalstill
Copy link
Copy Markdown
Author

Ummm, I'm happy to sign the CLA, but https://www.home-assistant.io/developers/cla/ implies there should be a link above for me to do that thing, and I can't see it...

@rohankapoorcom
Copy link
Copy Markdown
Member

@mikalstill, it looks like your link is https://home-assistant.io/developers/cla_sign_start/?pr=home-assistant/home-assistant#19732

The message from the home assistant bot had it (the word here was hyperlinked to that url).

@mikalstill
Copy link
Copy Markdown
Author

I swear that comment wasn't there before. Regardless, I'll sign the CLA now.

Comment thread homeassistant/components/rpi_gpio.py Outdated


class UnknownOrangePiBoard(Exception):
"""'board' config item not set"""
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

trailing whitespace

@fabaff
Copy link
Copy Markdown
Member

fabaff commented Jan 3, 2019

Note that the orangepi GPIO library requires access to /dev/mem, which I have resolved for now by running Home Assistant as root.

To be honest, I not a big fan of suggesting to run HA as root. How was this issue solved for RPi.GPIO?

Comment thread homeassistant/components/rpi_gpio.py Outdated

def setup(hass, base_config):
"""Set up the GPIO component."""
global GPIO_LIBRARY
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use global, we have hass.data.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I'll go have a look at examples.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Comment thread homeassistant/components/rpi_gpio.py Outdated
board = ORANGEPI_BOARDS.get(board_name)
_LOGGER.info('OrangePi %s board specified', board_name)

if not board_name:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All validation should be done with the Schema.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

board_name is only required if you specify an Orange Pi, there is no equivalent concept with Raspberry Pi GPIOs. Is there an existing example of how to conditionally validate that a config value is set dependant on another config value?

@mikalstill
Copy link
Copy Markdown
Author

Note that the orangepi GPIO library requires access to /dev/mem, which I have resolved for now by running Home Assistant as root.

To be honest, I not a big fan of suggesting to run HA as root. How was this issue solved for RPi.GPIO?

Totally agreed. That said, its not an as-root requirement, its a with-permissions-for-/dev/mem requirement. That can be done with filesystem permissions if required.

My understanding is that Raspberry Pi deals with this by having a kernel driver which exposes the GPIOs in a more friendly manner. I'm not opposed to doing that for OrangePi, but it will take a little time to do.

mikalstill added a commit to mikalstill/home-assistant that referenced this pull request Jan 4, 2019
@deece
Copy link
Copy Markdown

deece commented Jan 4, 2019

The Rpi.GPIO library first tries /dev/gpiomem (which is Broadcom specific, and has perms granted via udev), then falls back to /dev/mem (which will require perms).

We can solve the access issue for /dev/mem with some udev rules.

Having said that, after some discussion around the office at Ozlabs, /dev/mem is quite dangerous, any process that can access that can effectively access the memory of any process on the system, including the kernel, and library devs who access that should be admonished^H^H^H^H taken aside and taught how to abstract access via kernel driver.

In this case, we should have access to /sys/class/gpio, which in provided by the pinctrl subsystem on the Orange Pi. This library access GPIO via that: https://pypi.org/project/OPi.GPIO/ It will need a patch to support the Orange Pi Prime, but that seems pretty straightforward.

@deece
Copy link
Copy Markdown

deece commented Jan 9, 2019

It's worth noting that HassOS currently runs HomeAssistant as root, and passes /dev/mem through to the docker container (not that I recommend we take this path). I'll log this as an issue.

@mikalstill
Copy link
Copy Markdown
Author

Ok, so this latest patch does a few things:

  • Moves to a new GPIO library for OrangePi that does not require root (it uses sysfs not /dev/mem)
  • Removes the requirement to configure the OrangePi board, as it turns out they all seem to have the same GPIO pinout

I think that resolves all of fabaff's concerns?

@mikalstill
Copy link
Copy Markdown
Author

Hey @pvizeli, it was suggested I ping you about two things around this PR:

  • the CLA-Error label is now incorrect, but I don't know how to remove it. How do we do that thing?

  • also, the pin numbering scheme for OrangePi that makes the most sense is something called SUNXI. However, its not integers. How would we feel about relaxing the schema for pin numbers in components dependant on this one such as rpi_switch? I'd prefer to do that than to fork out a separate OrangePi switch component if possible.

Thanks!

mikalstill and others added 7 commits January 15, 2019 14:07
Instead of adding a new component for orangepi (which is a
raspberry pi clone), let's just extend the existing component
to support more than one family of boards.

I have tested this patch on a raspberry pi 3 and an orangepi
prime, in both cases with a LED on a GPIO controlled switch.
Note that the orangepi GPIO library requires access to /dev/mem,
which I have resolved for now by running Home Assistant as root.
This library doesn't require root or access to /dev/mem because
it uses the sysfs interface for GPIOs instead. It also doesn't
need to know what OrangePi board you're using, so the configuration
is simpler.
Its much less confusing, given there are two competing numbering
schemes.
mikalstill added a commit to mikalstill/home-assistant.io that referenced this pull request Jan 16, 2019
This update brings the documentation inline with what is proposed
in Home Assistant PR:

    home-assistant/core#19732
"""Set up the GPIO component."""
hass.data[DOMAIN] = {}

config = base_config.get(DOMAIN)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use dict[key] for required config keys and keys with default config schema values.

family_name = config.get(CONF_BOARD_FAMILY, DEFAULT_FAMILY)
lib_name = FAMILY_LIBRARIES.get(family_name)
_LOGGER.info('Configured to use board family %s', family_name)
_LOGGER.info('Will use %s as GPIO library', lib_name)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merge these logging messages to one.

if not lib_name:
raise UnknownBoardFamily('Unknown board family: %s'
% config.get(CONF_BOARD_FAMILY))
hass.data[DOMAIN][LIBRARY] = importlib.import_module(lib_name)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cache the imported lib in a local variable that we can use below.

self._state = None

rpi_gpio.setup_input(self._port, self._pull_mode)
rpi_gpio.setup_input(self._hass, self._port, self._pull_mode)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this to entity coroutine method async_added_to_hass.

"""Represent a binary sensor that uses Raspberry Pi GPIO."""

def __init__(self, name, port, pull_mode, bouncetime, invert_logic):
def __init__(self, hass, name, port, pull_mode, bouncetime, invert_logic):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't pass in hass. It will be set on the entity when it has been added to home assistant.

"""Representation of a Raspberry GPIO cover."""

def __init__(self, name, relay_pin, state_pin, state_pull_mode,
def __init__(self, hass, name, relay_pin, state_pin, state_pull_mode,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above.

def __init__(self, name, port, pull_mode, bouncetime, invert_logic):
def __init__(self, hass, name, port, pull_mode, bouncetime, invert_logic):
"""Initialize the RPi binary sensor."""
self._hass = hass
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this.

rpi_gpio.setup_output(self._relay_pin)
rpi_gpio.setup_input(self._state_pin, self._state_pull_mode)
rpi_gpio.write_output(self._relay_pin, 0 if self._invert_relay else 1)
rpi_gpio.setup_output(self._hass, self._relay_pin)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move to async_added_to_hass.

"""Representation of a Raspberry Pi GPIO."""

def __init__(self, name, port, invert_logic):
def __init__(self, hass, name, port, invert_logic):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above.

self._state = False
rpi_gpio.setup_output(self._port)
rpi_gpio.write_output(self._port, 1 if self._invert_logic else 0)
rpi_gpio.setup_output(self._hass, self._port)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move to async_added_to_hass.

@balloob
Copy link
Copy Markdown
Member

balloob commented Feb 21, 2019

This should not be part of the Raspberry Pi integration but instead be a new one. Over time, the integrations will diverge, and we will end up with a bunch of if…else statements. We don't want that.

@balloob
Copy link
Copy Markdown
Member

balloob commented Feb 26, 2019

This PR seems to have gone stale. Closing it.

@balloob balloob closed this Feb 26, 2019
@ghost ghost removed the in progress label Feb 26, 2019
@fabaff fabaff mentioned this pull request Mar 29, 2019
9 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants