使用 dbus 关闭 docker 容器内的 Raspberry Pi 和 python
Using dbus to poweroff Raspberry Pi inside docker container and python
我正在使用 BalenaOS 并构建一个 docker 容器,其中包含一些 python 可以感知何时按下按钮然后应该发送此命令:
dbus-send --system \
--print-reply=literal \
--dest=org.freedesktop.login1 \
/org/freedesktop/login1 \
"org.freedesktop.login1.Manager.PowerOff" boolean:true
我可以在这个容器中打开一个终端,运行 这个命令,它确实按预期工作。但是,按下按钮只会导致出现错误消息(显示在 post 的底部)
这是我的设置:
docker文件
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
编辑
我放弃了 dbus-python
因为 pydbus
它似乎产生了更好的结果并且似乎简化了问题但仍然吐出错误。可以在此处找到有关两者之间差异的更多信息 https://wiki.python.org/moin/DbusExamples
这是编辑后的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)
现在的输出是:
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)
如果我不得不猜测,我会说我在 python 脚本中做错了什么。没有正确使用 dbus。
感谢stovfl
问题是:
- 使用 dbus-python,但应该使用 pydbus 库。 dbus-python 已折旧。
- 我的
interface.PowerOff()
丢失了 True。应该是interface.PowerOff(True)
正确的 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 ["python", "button.py"]
我的requirements.txt
RPi.Gpio
pydbus
Pycairo
PyGObject
正确的python脚本是
#!/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)
帮助我找到答案的链接:
https://wiki.python.org/moin/DbusExamples
https://pygobject.readthedocs.io/en/latest/getting_started.html
Raspbian 靶心解决方案:
Sudo Edit /usr/share/polkit-1/actions/org.freedesktop.login1.policy
以更改 https://www.freedesktop.org/software/systemd/man/org.freedesktop.login1.html#Security 中所需的安全设置,例如允许“断电”
...
<action id="org.freedesktop.login1.power-off">
<description gettext-domain="systemd">Power off the system</description>
<message gettext-domain="systemd">Authentication is required to power off the system.</message>
<defaults>
<allow_any>yes</allow_any>
<allow_inactive>yes</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.set-wall-message</annotate>
</action>
<action id="org.freedesktop.login1.power-off-multiple-sessions">
<description gettext-domain="systemd">Power off the system while other users are logged in</description>
<message gettext-domain="systemd">Authentication is required to power off the system while other users are logged in.</message>
<defaults>
<allow_any>yes</allow_any>
<allow_inactive>yes</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.power-off</annotate>
</action>
...
Python:
import dbus
bus = dbus.SystemBus()
obj = bus.get_object('org.freedesktop.login1', '/org/freedesktop/login1')
iface = dbus.Interface(obj, 'org.freedesktop.login1.Manager')
iface.PowerOff(True)
对于多用户系统来说,允许不受挑战地访问 poweroff 并不理想,但对于我使用遥控钥匙关闭机器人的目的来说效果很好
我正在使用 BalenaOS 并构建一个 docker 容器,其中包含一些 python 可以感知何时按下按钮然后应该发送此命令:
dbus-send --system \
--print-reply=literal \
--dest=org.freedesktop.login1 \
/org/freedesktop/login1 \
"org.freedesktop.login1.Manager.PowerOff" boolean:true
我可以在这个容器中打开一个终端,运行 这个命令,它确实按预期工作。但是,按下按钮只会导致出现错误消息(显示在 post 的底部)
这是我的设置:
docker文件
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
编辑
我放弃了 dbus-python
因为 pydbus
它似乎产生了更好的结果并且似乎简化了问题但仍然吐出错误。可以在此处找到有关两者之间差异的更多信息 https://wiki.python.org/moin/DbusExamples
这是编辑后的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)
现在的输出是:
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)
如果我不得不猜测,我会说我在 python 脚本中做错了什么。没有正确使用 dbus。
感谢stovfl
问题是:
- 使用 dbus-python,但应该使用 pydbus 库。 dbus-python 已折旧。
- 我的
interface.PowerOff()
丢失了 True。应该是interface.PowerOff(True)
正确的 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 ["python", "button.py"]
我的requirements.txt
RPi.Gpio
pydbus
Pycairo
PyGObject
正确的python脚本是
#!/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)
帮助我找到答案的链接:
https://wiki.python.org/moin/DbusExamples
https://pygobject.readthedocs.io/en/latest/getting_started.html
Raspbian 靶心解决方案:
Sudo Edit /usr/share/polkit-1/actions/org.freedesktop.login1.policy
以更改 https://www.freedesktop.org/software/systemd/man/org.freedesktop.login1.html#Security 中所需的安全设置,例如允许“断电”
...
<action id="org.freedesktop.login1.power-off">
<description gettext-domain="systemd">Power off the system</description>
<message gettext-domain="systemd">Authentication is required to power off the system.</message>
<defaults>
<allow_any>yes</allow_any>
<allow_inactive>yes</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.set-wall-message</annotate>
</action>
<action id="org.freedesktop.login1.power-off-multiple-sessions">
<description gettext-domain="systemd">Power off the system while other users are logged in</description>
<message gettext-domain="systemd">Authentication is required to power off the system while other users are logged in.</message>
<defaults>
<allow_any>yes</allow_any>
<allow_inactive>yes</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.power-off</annotate>
</action>
...
Python:
import dbus
bus = dbus.SystemBus()
obj = bus.get_object('org.freedesktop.login1', '/org/freedesktop/login1')
iface = dbus.Interface(obj, 'org.freedesktop.login1.Manager')
iface.PowerOff(True)
对于多用户系统来说,允许不受挑战地访问 poweroff 并不理想,但对于我使用遥控钥匙关闭机器人的目的来说效果很好