| 1 | #!/usr/bin/env python |
|---|
| 2 | |
|---|
| 3 | """ |
|---|
| 4 | StormSiren |
|---|
| 5 | Copyright (C) 2008 Chris Freeze <cfreeze/cfreeze_com\> |
|---|
| 6 | |
|---|
| 7 | Redistribution and use in source and binary forms, with or without |
|---|
| 8 | modification, are permitted provided that the following conditions |
|---|
| 9 | are met: |
|---|
| 10 | |
|---|
| 11 | 1. Redistributions of source code must retain the above copyright |
|---|
| 12 | notice, this list of conditions and the following disclaimer. |
|---|
| 13 | 2. Redistributions in binary form must reproduce the above copyright |
|---|
| 14 | notice, this list of conditions and the following disclaimer in the |
|---|
| 15 | documentation and/or other materials provided with the distribution. |
|---|
| 16 | |
|---|
| 17 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
|---|
| 18 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
|---|
| 19 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
|---|
| 20 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
|---|
| 21 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
|---|
| 22 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|---|
| 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|---|
| 24 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|---|
| 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
|---|
| 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|---|
| 27 | """ |
|---|
| 28 | |
|---|
| 29 | """ |
|---|
| 30 | This is StormSiren a program inspired by the StormSiren application |
|---|
| 31 | written by Roy McManus <slorf/users_sourceforge_net>. Much like the |
|---|
| 32 | original StormSiren written by Roy McManus <slorf/users_sourceforge_net>, |
|---|
| 33 | this program is a simple script capable of scanning and providing |
|---|
| 34 | notifications of weather bulletins issued by the National |
|---|
| 35 | Weather Service. StormSiren supports a wide range of paging devices |
|---|
| 36 | and filtering of alert types per alert device. While inspired by |
|---|
| 37 | StormSiren, StormSiren is a complete rewrite that is capable of using |
|---|
| 38 | the new CAP/XML feeds provided at http://www.weather.gov/alerts/. |
|---|
| 39 | |
|---|
| 40 | For more information there is see the README.TXT file located in the root |
|---|
| 41 | of this directory. |
|---|
| 42 | """ |
|---|
| 43 | |
|---|
| 44 | from time import sleep |
|---|
| 45 | import string |
|---|
| 46 | |
|---|
| 47 | try: |
|---|
| 48 | import pyosd |
|---|
| 49 | except: |
|---|
| 50 | pass |
|---|
| 51 | |
|---|
| 52 | from AlertDevice import * |
|---|
| 53 | |
|---|
| 54 | DEFAULT_OSD_POSITION = "top" |
|---|
| 55 | DEFAULT_OSD_ALIGNMENT = "right" |
|---|
| 56 | DEFAULT_OSD_OFFSET = 20 |
|---|
| 57 | DEFAULT_OSD_TIMEOUT = 10 |
|---|
| 58 | DEFAULT_OSD_COLOR = '#990000' |
|---|
| 59 | DEFAULT_OSD_FONT = '-adobe-helvetica-bold-r-normal-*-24-*-*-*-*-*-iso8859-1' |
|---|
| 60 | |
|---|
| 61 | class OsdAlertDevice(AlertDevice): |
|---|
| 62 | def __init__(self,osdInfo,alerts,areas): |
|---|
| 63 | super(OsdAlertDevice,self).__init__(alerts,areas) |
|---|
| 64 | self.__osdInfo = osdInfo |
|---|
| 65 | self.log = logging.getLogger('OsdAlertDevice') |
|---|
| 66 | |
|---|
| 67 | self.log.setLevel(logging.INFO) |
|---|
| 68 | |
|---|
| 69 | def display(self): |
|---|
| 70 | super(OsdAlertDevice,self).display() |
|---|
| 71 | |
|---|
| 72 | def __str__(self): |
|---|
| 73 | str = "OsdAlertDevice\n" + \ |
|---|
| 74 | self.__osdInfo.__str__() + \ |
|---|
| 75 | super(OsdAlertDevice,self).__str__() |
|---|
| 76 | return str |
|---|
| 77 | |
|---|
| 78 | def send(self,alert): |
|---|
| 79 | self.log.debug("Sending OSD Alert") |
|---|
| 80 | self.__osdInfo.initOsd(len(alert.detailed)) |
|---|
| 81 | self.__osdInfo.sendOsd(alert.detailed) |
|---|
| 82 | self.log.debug("OSD Alert sent, waiting now") |
|---|
| 83 | self.__osdInfo.wait() |
|---|
| 84 | self.log.debug("Deinit OSD") |
|---|
| 85 | self.__osdInfo.delOsd() |
|---|
| 86 | |
|---|
| 87 | class OsdAlertDeviceInfo(object): |
|---|
| 88 | def __init__(self, |
|---|
| 89 | position = DEFAULT_OSD_POSITION, |
|---|
| 90 | alignment = DEFAULT_OSD_ALIGNMENT, |
|---|
| 91 | offset = DEFAULT_OSD_OFFSET, |
|---|
| 92 | timeout = DEFAULT_OSD_TIMEOUT, |
|---|
| 93 | color = DEFAULT_OSD_COLOR, |
|---|
| 94 | font = DEFAULT_OSD_FONT): |
|---|
| 95 | self.__position = position |
|---|
| 96 | self.__alignment = alignment |
|---|
| 97 | self.__offset = offset |
|---|
| 98 | self.__timeout = timeout |
|---|
| 99 | self.__color = color |
|---|
| 100 | self.__font = font |
|---|
| 101 | self.__osd = None |
|---|
| 102 | |
|---|
| 103 | def display(self): |
|---|
| 104 | print self.__str__() |
|---|
| 105 | |
|---|
| 106 | def initOsd(self,numlines): |
|---|
| 107 | if(self.__osd == None): |
|---|
| 108 | self.__osd = pyosd.osd(font = self.__font, |
|---|
| 109 | colour = self.__color, |
|---|
| 110 | timeout = self.__timeout, |
|---|
| 111 | pos = self.getPosition(), |
|---|
| 112 | offset = self.__offset, |
|---|
| 113 | align = self.getAlignment(), |
|---|
| 114 | lines = numlines) |
|---|
| 115 | |
|---|
| 116 | def wait(self): |
|---|
| 117 | if(self.__osd): |
|---|
| 118 | self.__osd.wait_until_no_display() |
|---|
| 119 | |
|---|
| 120 | def delOsd(self): |
|---|
| 121 | if(not self.__osd): |
|---|
| 122 | self.__osd._del() |
|---|
| 123 | |
|---|
| 124 | def getAlignment(self): |
|---|
| 125 | if(self.__alignment.lower() == "left"): |
|---|
| 126 | return pyosd.ALIGN_LEFT |
|---|
| 127 | elif(self.__alignment.lower() == "right"): |
|---|
| 128 | return pyosd.ALIGN_RIGHT |
|---|
| 129 | elif(self.__alignment.lower() == "center"): |
|---|
| 130 | return pyosd.ALIGN_CENTER |
|---|
| 131 | else: |
|---|
| 132 | return pyosd.ALIGN_LEFT |
|---|
| 133 | |
|---|
| 134 | def getPosition(self): |
|---|
| 135 | if(self.__position.lower() == "top"): |
|---|
| 136 | return pyosd.POS_TOP |
|---|
| 137 | elif(self.__position.lower() == "bottom"): |
|---|
| 138 | return pyosd.POS_BOT |
|---|
| 139 | elif(self.__position.lower() == "middle"): |
|---|
| 140 | return pyosd.POS_MID |
|---|
| 141 | else: |
|---|
| 142 | return pyosd.POS_TOP |
|---|
| 143 | |
|---|
| 144 | def sendOsd(self,str): |
|---|
| 145 | if(self.__osd): |
|---|
| 146 | lineno = 0 |
|---|
| 147 | for line in string.split(str,'\n'): |
|---|
| 148 | self.__osd.display(line,pyosd.TYPE_STRING, lineno) |
|---|
| 149 | lineno += 1 |
|---|
| 150 | |
|---|
| 151 | def __str__(self): |
|---|
| 152 | str = "OsdAlertDeviceInfo\n" |
|---|
| 153 | str += "\t Font: %s\n" % self.__font |
|---|
| 154 | str += "\t Color: %s\n" % self.__color |
|---|
| 155 | str += "\t Offset: %s\n" % self.__offset |
|---|
| 156 | str += "\t Timeout: %i\n" % self.__timeout |
|---|
| 157 | str += "\t Position: %s:%i\n" % (self.__position, self.getPosition()) |
|---|
| 158 | str += "\t Alignment: %s:%i\n" % (self.__alignment, self.getAlignment()) |
|---|
| 159 | if(self.__osd): |
|---|
| 160 | str += "\t Num Lines: %i\n" % (self.__osd.get_number_lines()) |
|---|
| 161 | else: |
|---|
| 162 | str += "\t OSD not initialized\n" |
|---|
| 163 | return str |
|---|
| 164 | |
|---|
| 165 | def getWaitTime(self): |
|---|
| 166 | return self.__wait_time |
|---|
| 167 | |
|---|
| 168 | wait_time = property(getWaitTime,None,None) |
|---|