Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using dbus to poweroff Raspberry Pi inside docker container and python

I'm using BalenaOS and building a docker container with some python that senses when a button is pressed and then is supposed to send this command:

dbus-send --system \
    --print-reply=literal \
    --dest=org.freedesktop.login1 \
    /org/freedesktop/login1 \
   "org.freedesktop.login1.Manager.PowerOff" boolean:true

I can open a terminal inside this container, run this command, and it DOES work exactly as intended. However, pressing the button only results in this in error messages (shown at bottom of post)

Here is my setup:

dockerfile

FROM balenalib/%%BALENA_MACHINE_NAME%%-debian-python:3.7.4

# Enable systemd init system
ENV INITSYSTEM off

# Set the working directory
WORKDIR /usr/src/app

RUN install_packages git dbus gnome-common

RUN apt-get update
RUN apt install python3-gi python3-gi-cairo gir1.2-gtk-3.0

# Upgrade pip
RUN pip install --upgrade pip
COPY requirements.txt .
RUN pip install --user -r requirements.txt --no-cache-dir --disable-pip-version-check \
                --index-url https://www.piwheels.org/simple

# Copy everything into the container
COPY . ./
#Make sure scripts in .local are usable:
ENV PATH=/root/.local/bin:$PATH
ENV DBUS_SYSTEM_BUS_ADDRESS=unix:path=/host/run/dbus/system_bus_socket
# Start application
CMD ["bash", "start.sh"]

requirements.txt

RPi.Gpio
dbus-python

start.sh

#!/usr/bin/env bash

## connect to the host's system bus from the application container
export DBUS_SYSTEM_BUS_ADDRESS=unix:path=/host/run/dbus/system_bus_socket

EDIT

I abandoned dbus-python for pydbus It seems to yield a better result and seems to simplify the problem but still spits an error. More info on the difference between the two can be found here https://wiki.python.org/moin/DbusExamples

Here is the edited python

button.py

import RPi.GPIO as GPIO
import time
import pydbus
import gi

# Set GPIO mode: GPIO.BCM or GPIO.BOARD
GPIO.setmode(GPIO.BOARD)

# Set pin 5 an an input, and enable the internal pull-up resistor
GPIO.setup(5, GPIO.IN, pull_up_down=GPIO.PUD_UP)

oldButtonState1 = True

while True:
    buttonState1 = GPIO.input(5)

    if buttonState1 != oldButtonState1 and buttonState1 == False :
        bus = pydbus.SystemBus()
        logind = bus.get('.login1')['.Manager']
        logind.PowerOff()

    oldButtonState1 = buttonState1

time.sleep(1)

The output is now:

21.12.19 11:33:53 (-0800)  button      logind.PowerOff()
21.12.19 11:33:53 (-0800)  button    File "/root/.local/lib/python3.7/site-packages/pydbus/proxy_method.py", line 62, in __call__
21.12.19 11:33:53 (-0800)  button      raise TypeError(self.__qualname__ + " missing {} required positional argument(s)".format(-argdiff))
21.12.19 11:33:53 (-0800)  button  TypeError: org.freedesktop.login1.Manager.PowerOff missing 1 required positional argument(s)
21.12.19 11:33:59 (-0800)  button  button.py:12: RuntimeWarning: A physical pull up resistor is fitted on this channel!
21.12.19 11:33:59 (-0800)  button    GPIO.setup(5, GPIO.IN, pull_up_down=GPIO.PUD_UP)

If I had to guess I'd say I'm doing something wrong in the python script. Not utilizing dbus correctly.

like image 648
Kingston Avatar asked Nov 17 '25 13:11

Kingston


1 Answers

Thanks to stovfl

The issue was:

  1. Using a dbus-python, but what SHOULD be used is the pydbus library. dbus-python is depreciated.
  2. My interface.PowerOff() was missing True. It should be interface.PowerOff(True)

The correct dockerfile is:

FROM balenalib/%%BALENA_MACHINE_NAME%%-debian-python:3.7.4

# Enable systemd init system
ENV INITSYSTEM off

# Set the working directory
WORKDIR /usr/src/app

RUN install_packages git dbus gnome-common

RUN apt-get update
RUN apt install python3-gi python3-gi-cairo gir1.2-gtk-3.0

# Upgrade pip
RUN pip install --upgrade pip
COPY requirements.txt .
RUN pip install --user -r requirements.txt --no-cache-dir --disable-pip-version-check \
                --index-url https://www.piwheels.org/simple

# Copy everything into the container
COPY . ./
#Make sure scripts in .local are usable:
ENV PATH=/root/.local/bin:$PATH
ENV DBUS_SYSTEM_BUS_ADDRESS=unix:path=/host/run/dbus/system_bus_socket
# Start application
CMD ["python", "button.py"]

My requirements.txt

RPi.Gpio
pydbus
Pycairo
PyGObject

The correct python script is

#!/usr/bin/env python3
#!
import RPi.GPIO as GPIO
import time
import pydbus
import gi

# Set GPIO mode: GPIO.BCM or GPIO.BOARD
GPIO.setmode(GPIO.BOARD)

# Set pin 5 an an input, and enable the internal pull-up resistor
GPIO.setup(5, GPIO.IN, pull_up_down=GPIO.PUD_UP)

oldButtonState1 = True

while True:
    buttonState1 = GPIO.input(5)

    if buttonState1 != oldButtonState1 and buttonState1 == False :
        bus = pydbus.SystemBus()
        logind = bus.get('.login1')['.Manager']
        logind.PowerOff(True)

    oldButtonState1 = buttonState1

time.sleep(1)

Links that helped me find the answers:

https://wiki.python.org/moin/DbusExamples

https://fhackts.wordpress.com/2019/08/08/shutting-down-or-rebooting-over-dbus-programmatically-from-a-non-root-user/

https://pygobject.readthedocs.io/en/latest/getting_started.html

like image 141
Kingston Avatar answered Nov 20 '25 01:11

Kingston



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!