Using a Raspberry Pi 3B+'s GPIO pinout, what would be the best way to add a button that can interact with the balenaOS to “Halt” balenaOS. Raspberry pi is able to Halt in raspbian:
Basically what I’m trying to achieve is the ability to use one button to both sleep the device and once pressed again, to turn on the device. Does Balena have any suggestions for achieving this? Even if it isn’t a true sleep but shuts down as many things as possible but doesn’t actually cut power
I seem to recal a GPIO pin that, when grounded/pulled high, would start a Pi from a halt state. You could wire this up and then run a service to hook the GPIO event (maybe in Python) and then call the DBUS power off command mentioned above. That’s the only thing I can think of right now, I hope it helps.
where your script calls subprocess.call(..., I’m not sure if your device supports suspend to ram, but that might work. I couldn’t find the halt equivalent on the login1.Manager dbus interface, suspend seems the closest
So would this require an internet connection to turn off then? The Balena poweroff function or shutdown is actually a halt. The device CAN be turned back on by shorting pins 5 and 6, the i2c pins. That is working as of right now. That’s just an inherent feature of all Raspberry Pis. What I need to be able to do is to push the same button to send a poweroff or shutdown command, preferably all locally and without a dependency of an internet connection.
Hey there! it’s probably worth checking out this library: https://pypi.org/project/dbus-python/ . I 'd experiment with some dbus-python examples onlite too. Hope it helps!
@shaunmulligan@gelbal What if you were running this inside the HostOS instead of a container? Would that simplify things or would I still need to use dbus?
Hi @KingstonSteele, you could run shutdown command on hostOS to shut down RPi. As for simplifying things, it depends on how you’d like to setup this. Coding such control in the service container would probably make it easier to maintain it. As the setup will be part of the application code.
Having said these, I’m not sure if RPi supports sleep mode. Searching online, I see several notes about RPi not having any sophisticated power management capabilities. (this is one of the things balenaFin addresses)
I was able to get back onto this. I’m committed to finding a solution and sharing it for others.
So I was able to make some stuff happen and get some error logs, I went through them all (things like exporting dbus, etc) but now I have no log at all when I press the button. So no errors but also no shutdown just this:
<Interface <ProxyObject wrapping <dbus._dbus.SystemBus (system) at 0x769f41b0> :1.1 /org/freedesktop/login1 at 0x769ef690> implementing 'org.freedesktop.login1.Manager.PowerOff' at 0x769ef830>
#!/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
python button.py
button.py
import RPi.GPIO as GPIO
import time
import dbus
# 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 = dbus.SystemBus()
boolean = dbus.Boolean(True)
remote_object = bus.get_object('org.freedesktop.login1', '/org/freedesktop/login1')
interface = dbus.Interface(remote_object, 'org.freedesktop.login1.Manager.PowerOff')
print interface
oldButtonState1 = buttonState1
time.sleep(1)
Once this is solved it will wake using the same button. I can power the device down from the dashboard/balena cloud and wake it back up whenever by just pressing the button. So when this get’s solved, it’ll be a pretty cool, handy feature.
Hi @KingstonSteele that would indeed be a very handy feature. One thing that might help troubleshoot is to run the 'org.freedesktop.login1.Manager.PowerOff' command from within your container manually using dbus-send and simultaneously tail the journal logs on the hostOS. If that doesn’t work we know there is probably some problem on the OS level
One other thing I noticed is that you said you can shutdown the pi from the dashboard and bring it back via the button. If that works, you could wire the button call the supervisor shutdown API endpoint from your container (this does NOT need an internet connection as its all over local docker network) and that will shutdown the device in the same way it does from the dashboard
FROM resin/%%RESIN_MACHINE_NAME%%-python
#switch on systemd init system in container
ENV INITSYSTEM on
RUN install_packages dbus
ENV DBUS_SYSTEM_BUS_ADDRESS=unix:path=/host/run/dbus/system_bus_socket
# pip install python deps from requirements.txt
# For caching until requirements.txt changes
COPY ./requirements.txt /requirements.txt
RUN pip install -r /requirements.txt
COPY . /usr/src/app
WORKDIR /usr/src/app
CMD ["python", "button.py"]
But I get this error during build:
[button] /bin/sh: 1: install_packages: not found
[button]
[button] Removing intermediate container 91a25804abde
[button] The command '/bin/sh -c install_packages dbus' returned a non-zero code: 127
You can install the dbus package using the package management system, which in your case seems to be apt-get. Something like RUN apt-get update && apt-get install -y dbus should do the right thing, though we really recommend switching base images as soon as possible. Do note all the breaking changes listed here: https://www.balena.io/docs/reference/base-images/base-images/#major-changes.
FROM balenalib/%%BALENA_MACHINE_NAME%%-debian-python:3.7.4
# Enable systemd init system
ENV INITSYSTEM on
# Set the working directory
WORKDIR /usr/src/app
RUN install_packages dbus
# 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"]
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
python button.py
button.py
import RPi.GPIO as GPIO
import time
import dbus
# 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 = dbus.SystemBus()
boolean = dbus.Boolean(True)
remote_object = bus.get_object('org.freedesktop.login1', '/org/freedesktop/login1')
interface = dbus.Interface(remote_object, 'org.freedesktop.login1.Manager.PowerOff')
print (interface)
oldButtonState1 = buttonState1
time.sleep(1)
The result is still:
<Interface <ProxyObject wrapping <dbus._dbus.SystemBus (system) at 0x768e2fc0> :1.0 /org/freedesktop/login1 at 0x768f13d0> implementing 'org.freedesktop.login1.Manager.PowerOff' at 0x76582910>