In this series, we will make a notification lamp using Raspberry Pi.
This time, the third time, is the main part that controls the entire "notification lamp". This series is now complete.
Alert Buster (Abu for short) is responsible for acquiring OpsGenie Alert information via the Detector, identifying the status of the monitored object, and setting the LED display. It's also Abu's job to ring the chime only once when a new Alert occurs.
Only one status can display the "notification lamp" for the Alert status that may exist more than once at the same time. Therefore, prioritize the states to display the highest priority state.
Abu handles the following 6 types of states. There are two levels, "Error" and "Warning". An "error" is something that you need to deal with in a hurry, and a "warning" is something that you are not in a hurry but need to confirm. There are two states, whether or not they have been recognized.
"Unknown" is used when the status is unknown, such as immediately after startup or due to a network problem. Decide the color to be assigned to each state and the blinking cycle. For the color names such as "Magenta", use the ones defined in Led.COLORS of the previous article.
priority | Alert type | Cognitive status | State value | color | Flickering cycle | Note |
---|---|---|---|---|---|---|
1 | unknown | - | 1 | Magenta | 0 (no blinking) | |
2 | error | Unrecognized | 2 | Red | 0.5 seconds | |
3 | Warning | Unrecognized | 4 | Yellow | 2 seconds | |
4 | error | Recognized | 8 | Green | 2 seconds | |
5 | Warning | Recognized | 16 | Green | 6 seconds | |
6 | New error | - | 32 | - | - | For chimes |
7 | New warning | - | 64 | - | - | For chimes |
8 | normal | - | 0 | Blue | 8 seconds |
Abu treats these states as a single integer value "state value". "State value" is assigned each bit value of the binary number so that it can be easily handled by bit operation. In "normal", all bits are 0, so there is no bit allocation.
Internally, the logical sum of 7 bits including the chime control flag in the above table is used as one state value. For example, if there is a new error that has not yet been recognized (before the chime sounds), the state value is 0x22.
The state value is represented by a single integer value that has a meaning for each bit, but you may use Python's Set type with an emphasis on readability.
When a new error or warning is found, the chime will sound only once to make it easier to notice. The chime plays the prepared sound file by passing it to the aplay command.
python
$ aplay --quiet /usr/share/sounds/alsa/Rear_Center.wav
In advance, connect a speaker to the earphone jack or USB port of the main unit and set it so that sound can be heard. Reference: https://www.google.co.jp/search?q=raspberrypi+aplay
The chime sound source can be any format supported by aplay. In Abu, I used the following from freesound.org. If you register as a user, you can download it, so check the license and use it.
Warning I chose a modest sound, as long as I could notice it. 112860__paulnorthyorks__eighties-synth.wav http://www.freesound.org/people/paulnorthyorks/sounds/112860/
Error I chose a sound that feels tense. The following sounds are processed to create and use a sound source that repeats three times. 204425__jaraxe__alarmx3.wav http://www.freesound.org/people/JarAxe/sounds/204425/ I used Audacity for processing.
Abu's work is as follows.
--Initialize Detector --Launch LED Deamon --Repeat the following --Call Detector to get a list of Alerts --Collect Alert Lists and Create Status Values --Set LED display according to the status value --Sound a chime if there is a new error or warning --Sleep for 1 minute
$ ./abu.py ********-****-****-****-************
********-****-****-****-************
For the part, specify the opsgenie api key introduced in the previous article.
When registering in cron so that it starts automatically when the OS starts, it is recommended to add it to cron as follows, for example.
$ crontab -e
@reboot cd path-to-module-dir;./abu.py ********-****-****-****-************ >/dev/nul 2>&1
abu.py
#!/usr/bin/env python
#coding:utf-8
import time
import os
from opsgenie import OpsGenie
from led_deamon import LedDeamon
class Abu(object):
DOWN = 1
ERR_UNACKED = 2
WARN_UNACKED = 4
ERR_ACKED = 8
WARN_ACKED = 16
ERR_NEW = 32
WARN_NEW = 64
NORMAL = 0
ERROR_SOUND = "./204425__jaraxe__alarm-2.wav"
WARNING_SOUND = "./112860__paulnorthyorks__eighties-synth.wav"
STATE_MAP = {
DOWN: {"color": "Magenta", "interval": "0"},
ERR_UNACKED: {"color": "Red", "interval": "0.5"},
WARN_UNACKED: {"color": "Yellow", "interval": "4"},
ERR_ACKED: {"color": "Green", "interval": "4"},
WARN_ACKED: {"color": "Green", "interval": "8"},
NORMAL: {"color": "Blue", "interval": "8"}}
def _state2mode(self, state):
if state == Abu.NORMAL:
return Abu.STATE_MAP[Abu.NORMAL]
for s in (Abu.DOWN, Abu.ERR_UNACKED, Abu.WARN_UNACKED,
Abu.ERR_ACKED, Abu.WARN_ACKED):
if state & s:
return Abu.STATE_MAP[s]
else:
return Abu.STATE_MAP[Abu.NORMAL]
return None
def __init__(self, url, api_key):
self.opsgenie = OpsGenie(url, api_key)
def _summarize(self, list):
state = Abu.NORMAL
if list is None:
state = Abu.DOWN
else:
for l in list:
if l["error"]:
if l["acknowledged"]:
state |= Abu.ERR_ACKED
else:
state |= Abu.ERR_UNACKED
if l["new"]:
state |= Abu.ERR_NEW
else:
if l["acknowledged"]:
state |= Abu.WARN_ACKED
else:
state |= Abu.WARN_UNACKED
if l["new"]:
state |= Abu.WARN_NEW
return state
def start(self):
ld = LedDeamon()
ld.set_mode(self._state2mode(Abu.DOWN))
ld.start()
while True:
alert_list = self.opsgenie.detector()
# print alert_list
state = self._summarize(alert_list)
# print hex(state)
mode = self._state2mode(state)
if mode:
ld.set_mode(mode)
if state & Abu.ERR_NEW:
os.system("aplay " + Abu.ERROR_SOUND + "&")
else:
if state & Abu.WARN_NEW:
os.system("aplay " + Abu.WARNING_SOUND + "&")
time.sleep(60)
if __name__ == '__main__':
import sys
if len(sys.argv) != 2:
print("Usage: %s 'api-key for your OpsGenie account'." % sys.argv[0])
print("Example: %s ********-****-****-****-************." % sys.argv[0])
print("You can get your OpsGenie account at https://www.opsgenie.com.")
exit()
apiKey = sys.argv[1]
a = Abu(apiKey)
a.start()
Python studyers I tried using Raspberry Pi. There are also libraries that are cheap, powerful and easy to use GPIOs, and I found that they are a great match for these uses. There were some problems such as LED color control by PWM, asynchronous processing, handling of state values, OpsGenie cooperation, etc., but fortunately, we were able to find a reasonable solution for each, and we were able to complete it. I did. The "notification lamp" produced this time blends into the atmosphere of the workplace without any discomfort, and is useful in actual operation. If you are interested, please give it a try.
This series concludes with this article, but I'll post it again when I have the next idea.
Recommended Posts