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:
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"]
RPi.Gpio
dbus-python
#!/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
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
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.
Thanks to stovfl
The issue was:
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With