Home

Awesome

myGPIOd

myGPIOd is a lightweight GPIO controlling framework. It is written in C and has no hard dependencies but the libgpiod2 library version 2.

It consists of a daemon, a client library and a command line tool. It is designed to run on Raspberry PIs and similar devices.

I wrote this tool primarily for myMPDos and myMPD.

myGPIOd can communicate natively with MPD and also integrates nicely with all HTTP APIs.

Features

Installation

Build

Building myGPIOd is straight forward.

Dependencies

Only the current Fedora release packages the version 2 of libgpiod. If libgpiod version 2 is not found, the cmake script compiles it as a static library.

Build myGPIOd

This builds and installs the mygpiod daemon, mygpioc command line tool, the shared library libmygpio, the associated header files for development and the documentation.

  1. Get myGPIOd tarball from GitHub
  2. Extract myGPIOd tarball and change path to this directory
  3. Run cmake: cmake -B build -DCMAKE_INSTALL_PREFIX:PATH=/usr -DCMAKE_BUILD_TYPE=Release .
  4. Build: make -C build
  5. Install (as root): make -C build install

Run

myGPIOd needs rw access to the gpio chip device (e. g. /dev/gpiochip0).

/usr/bin/mygpiod [/etc/mygpiod.conf]

The cmake install script creates a startup script for systemd, openrc or sysVinit.

Systemd

You must enable and start the service manually. Use systemctl enable mygpiod to enable myGPIOd at startup and systemctl start mygpiod to start myGPIOd now.

myGPIOd logs to STDERR, you can see the live logs with journalctl -fu mygpiod.

The default myGPIOd service unit uses the DynamicUser= directive, therefore no static mygpiod user is created. If you want to change the group membership of this dynamic user, you must add an override.

Example: add the mygpiod user to the gpio group

mkdir /etc/systemd/system/mygpiod.service.d
echo -e '[Service]\nSupplementaryGroups=gpio' > /etc/systemd/system/mygpiod.service.d/gpio-group.conf

Docker

Example docker compose file to start myGPIOd.

---
version: "3.x"
services:
  mygpiod:
    image: ghcr.io/jcorporation/mygpiod/mygpiod
    container_name: mygpiod
    network_mode: "host"
    user: 1000:1000
    environment:
      - MPD_HOST=localhost
    volumes:
      - /dev/gpiochip0:/dev/gpiochip0
      - /etc/mygpiod.conf:/etc/mygpiod.conf
      - /etc/mygpiod.d/:/etc/mygpiod.d/
    restart: unless-stopped

To run mygpioc in the already running mygpiod container:

docker exec mygpiod mygpioc gpiolist

Configuration steps

Events

Events are triggered through changes of input GPIO values.

EVENTDESCRIPTION
fallingState of GPIO has changed from active to inactive.
risingState of GPIO has changed from inactive to active.
long_pressGPIO was pressed long. Event is triggered after configurable delay.
long_press_releaseGPIO changing it's state after a long press event.

Actions

Each event can have multiple actions. Actions and its arguments are delimited by a colon, arguments are delimited by space.

ACTIONARGUMENTSDESCRIPTION
gpioblink<gpio> <timeout_ms> <interval_ms>Toggle the value of the GPIO in given timeout and interval. Set interval to 0 to blink only once.
gpioset<gpio> <active|inactive>Sets the value of a GPIO.
gpiotoggle<gpio>Toggles the value of a GPIO.
http{GET|POST} {uri} [{content-type} {postdata}]Submits a HTTP request in a new child process. If postdata starts with <</, the string after the << is interpreted as an absolute filepath from which the postdata is read. Requires libcurl.
lua{lua function} [{option1} {option2} ...]Calls a user defined lua function.
mpc{mpd command} [{option1} {option2} ...]Connects to MPD and issues the command with options. It uses the default connection settings from libmpdclient. A maximum of 10 options are supported. Requires libmpdclient.
mympd{uri} {partition} {script}Calls the myMPD api to execute a script in a new child process. Requires libcurl.
system{command}Executes an executable or script in a new child process. No arguments are allowed.

myGPIOd can take actions on rising, falling and long_press events. Long press is triggered by a falling or rising event and does not disable the triggering event, but the release event. To use a button for normal press and long_press request both events and use one event for long and the other for short press. The example below illustrates this.

Lua

The lua action calls user defined lua functions. The lua script itself is loaded on startup of myGPIOd (lua_file configuration setting). All lua functions in this file are registered and can be called with the lua action.

myGPIOd registers custom lua functions to provide access to the actions. The functions return 0 on success, else 1.

Lua functionDescription
gpioBlink({GPIO}, {timeout_ms}, {interval_ms})Toggle the value of the GPIO in given timeout and interval.
gpioGet({GPIO})Returns the GPIO state: 1 = active, 0 = inactive
gpioSet({GPIO}, {1|0})Sets the state of an output GPIO: 1 = active, 0 = inactive
gpioToggle({GPIO})Toggles the state of an output GPIO.
http({GET|POST}, {uri}, {content-type}, {postdata})Submits a HTTP request in a new child process. This is an async function.
mpc({mpd protocol command})Runs a mpd protocol command.
mympd({uri}, {partition}, {script})Calls the myMPD api to execute a script in a new child process. This is an async function.
system({command})Executes an executable or script in a new child process. This is an async function.

Example gpio config

# Call the lua function `testFunc` with the argument `testArg` on rising event.
action_rising = lua:testFunc testArg

Example lua file

function changeMPDvolume()
  -- This example function can be used to change the MPD volume with a rotary encoder
  -- Get value of the GPIOs
  clk = gpioGet(4)
  dt = gpioGet(5)
  -- Check rotation direction
  if clk == dt then
    mpc("volume 5")
  else
    mpc("volume -5")
  end
end

Example configuration

This example configuration does the following:

/etc/mygpiod.conf

# GPIO chip to use
chip = /dev/gpiochip0

# The loglevel
loglevel = info

# Log to stdout
syslog = 0

# Directory for GPIO configuration files
gpio_dir = /etc/mygpiod.d

/etc/mygpiod.d/3.in

# Configuration file for GPIO 3 as input
# Request falling and rising events
event_request = both

# Active is high
active_low = false

# Enable the internal pull-up resistor
bias = pull-up

# Short press does a poweroff
# The rising event is not triggered if GPIO 6 is pressed longer than 2000 ms.
action_rising = system:/usr/local/bin/poweroff.sh

# Reboot on long press and activate a LED for maximal 2s while GPIO 6 is pressed.

# Set GPIO 6 active on falling
action_falling = gpioset:6 active

# Enable long press for falling.
long_press_event = falling

# Set the long press timeout to 2000 ms.
long_press_timeout = 2000

# Disable the long press interval.
long_press_interval = 0

# Action for long press is to run a script.
long_press_action = system:/usr/local/bin/reboot.sh

# Action for releasing the button after a long press is to toggle the value of GPIO 6.
long_press_release_action = gpiotoggle:6

/etc/mygpiod.d/4.in

# Configuration file for GPIO 4 as input
# Request the falling event
event_request = falling

# Enable the internal pull-up resistor
bias = pull-up

# Use libmpdclient to connect to mpd and send the command `next`
action_falling = mpc:next

/etc/mygpiod.d/5.out

# Configuration file for GPIO 5 as output
# Set the GPIO to active
value = active

/etc/mygpiod.d/6.out

# Configuration file for GPIO 6 as output
# Set the GPIO to inactive
value = inactive

/etc/mygpiod.d/7.in

# Configuration file for GPIO 7 as input
# Request the falling event
event_request = falling

# Enable the internal pull-up resistor
bias = pull-up

# Enable long press action for the falling event
long_press_event = falling

# Set initial long press timeout to 100 ms
long_press_timeout = 100

# Set interval to 500 ms, action is repeated in this interval until the value changes again
long_press_interval = 500

# Use libmpdclient to connect to mpd and send the command `volume +5`
# This increases the volume by 5 percent
long_press_action = mpc:volume +5

/etc/mygpiod.d/8.in

# Configuration file for GPIO 8 as input
# Request the falling event
event_request = falling

# Enable the internal pull-up resistor
bias = pull-up

# Execute the Jukebox script through the myMPD API
action_falling = gpioblink:6 1000 0
action_falling = mympd:https://127.0.0.1 default Jukebox

Protocol

myGPIOd can be controlled and queried through a simple line-based text protocol.

socat unix-client:/run/mygpiod/socket stdio

Command line client

The mygpioc command line client connects to the socket /run/mygpiod/socket to control myGPIOd.

mygpioc -h

Client library

The client library is documented in the header files. You can use doxygen to create the html documentation locally.

You can find a usage example here.

The mygpioc command line client is also based on this library.

Copyright

2020-2024 Juergen Mang mail@jcgames.de