Button press daemon

As you've seen from my other posts, I have a couple of lamps at home, controlled by homekit. I also have a daemon on the pi that does (slightly inaccurate) PWM to control LEDs for showing the current weather forecast (look around my various blogs or ask here for links if you want to see how each of these works).

I've added a couple of useful functions to the daemon and recently upgraded it to be a bit more of a packaged service (see the github page). It's also in it's own repo now.

The last feature I added was I wanted some way to capture inputs not just output voltages.

There are already good solutions on the pi, many of them written in python, that will read input pin values, and about 7 years ago, someone patched the kernel to allow interrupt drive, an addition to sysfs to indicate you want to write code that blocks on a device with a poll() or select(). Probably the best solution for most people will be to use this mechanism within their own C program or (even better for most), just use the nice python wrappers people have built.

But where's the fun in that? :) I always like to get to the bottom of things. The dgpio daemon I wrote controls pins directly using /dev/gpiomem to memory map the gpio pins then flipping hardware directly, making it fast. The daemon runs one thread per controlled pin, turning it on/off for pwm on a regular duty cycle. The config is controlled by simple text commands sent to a FIFO. The daemon contains features you won't need from earlier iterations but it's useable. Now I've added an extra command set i:12:99229 ... for input on pin 12 (for example). What does it do? Well, I figured in reality I'm going to want to run a script or program or similar when the pin is pressed. But how can the daemon do that? Exec/fork inside the daemon sounds like a world of pain and difficult to simply configure so I took a cheap option (there are many) and used unix signals!

The above config says on pin change (rising) for pin 12, send SIGUSR1 to pid 99229.

I then wrote a simple script like this:

#! /bin/bash

function toggleLamp {
if (exit $(($(i2cget -y 1 0x23 0x07))))
then
  i2cset -y 1 0x23 0x07 01
else
i2cset -y 1 0x23 0x07 00
fi
}

trap toggleLamp SIGUSR1

echo i:12:$$ > /var/run/dgpio/dgpio

while true
do
sleep 1
done

And ran it as a systemd unit.  This just runs forever, sleeping for a second most of the time (to avoid excessive CPU use) and waits for signals, turning the SwiftForArduino controlled corner lamp on/off.

Another example, this is the one you can see Florence demonstrating on the Facebook page...

#! /bin/bash

function toggleFairyLights {
if (exit $(($(grep 'pin 18' /var/log/dgpio/dgpio.stats|grep -o 'power = [01]'|cut -f 3 -d ' '))))
then
  echo p:18:01 > /var/run/dgpio/dgpio
else
  echo p:18:00 > /var/run/dgpio/dgpio
  fi
}

trap toggleFairyLights SIGUSR1

echo i:20:$$ > /var/run/dgpio/dgpio

while true
do
sleep 1
done

It's actually sending a command down the socket to the dgpio daemon itself.

The slight latency you see in the video is from the sleep command, which seems to need to complete the sleep command before the trap callback is called. This seems an acceptable balance to me (https://stackoverflow.com/questions/27694818/interrupt-sleep-in-bash-with-a-signal-traphttp://mywiki.wooledge.org/SignalTrap#When_is_the_signal_handled.3F) although I think it could be sped up (and CPU usage reduced) using these links. Maybe some day!




Comments

Popular posts from this blog

Halloween LED lights on a plastic trick or treat cauldron

All about bootloaders

Pushing the limits