Publish 0.6 - migration to Python 3 and systemd-journal support

This commit is contained in:
Dan Srebnick 2017-09-15 07:22:08 -04:00
parent 616f3f2b5e
commit ac275bee56
6 changed files with 101 additions and 54 deletions

12
README
View File

@ -3,13 +3,13 @@ https://github.com/K2DLS/noaacap/wiki/noaacap
ABOUT NOAACAP
This software is written in python 2.7 and has been tested with aprx 2.9.x.
This software is written in python 3.4 and has been tested with aprx 2.9.x.
If you are running a version < 2.9.0 you should first update aprx. The current
release may be found at http://thelifeofkenneth.com/aprx/debs/.
Once you are running aprx >= 2.9, install noaacap:
Install via sudo dpkg -i noaacap-0.5.deb. Then, to satisfy the dependencies,
Install via sudo dpkg -i noaacap-0.6.deb. Then, to satisfy the dependencies,
run sudo apt-get -f install.
CONFIGURATION
@ -23,10 +23,16 @@ cycle-size 2m
beacon via WIDE2-1 \
srccall N0CALL-13 \
timeout 20 \
exec /usr/local/bin/noaacap.py
</beacon>
The timeout was needed on my older and slower single core Raspberry Pi Model B.
The aprx default timeout is 10 seconds and the timeout may not be needed on a
RPi 2 or newer. If you need lots of "BEACON EXEC abnormal close" messages in
aprx.log, then you likely need to add the timeout.
The program will check for a new alert or update every 2 minutes, but only
send if there is a change.
@ -50,4 +56,4 @@ k2dls@k2dls.net with the callsign-SSID of your APRS station that is sending
weather alerts via this program.
Dan Srebnick, K2DLS
08/19/2017
09/13/2017

View File

@ -1,5 +1,5 @@
Package: noaacap
Version: 0.5
Version: 0.6
Section: hamradio
Priority: extra
Maintainer: Dan Srebnick <k2dls at k2dls.net>

View File

@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/python3
## Author: Dan Srebnick, K2DLS
## License: BSD-2-Clause (/usr/local/share/noaacap/LICENSE)
@ -6,49 +6,84 @@
##
## See /usr/local/share/noaacap/CHANGELOG for change history
##
version = "0.5"
version = "0.6"
import sys
import pytz, datetime
import pytz
import datetime
import string
import requests
from bs4 import BeautifulSoup
import bsddb
import os
import ConfigParser
from bsddb3 import db
from os import remove
import os.path
import configparser
import re
import logging
from systemd.journal import JournalHandler
log = logging.getLogger('noaacap')
log.addHandler(JournalHandler(SYSLOG_IDENTIFIER='noaacap'))
log.setLevel(logging.INFO)
log.info("Starting")
if len(sys.argv) == 2 and sys.argv[1] == '-v':
print "noaacap.py by K2DLS, version " + version
print
print "A weather alert beacon exec for aprx >= 2.9"
print "Licensed under the BSD 2 Clause license"
print "Copyright 2017 by Daniel L. Srebnick"
print
print("noaacap.py by K2DLS, version " + version + "\n")
print("A weather alert beacon exec for aprx >= 2.9")
print("Licensed under the BSD 2 Clause license")
print("Copyright 2017 by Daniel L. Srebnick\n")
sys.exit(0)
# We need this function early in execution
def Exiting():
log.info("Exiting")
print()
exit(0)
conffile = '/etc/noaacap.conf'
if not os.path.isfile(conffile):
exit("\nError: " + conffile + " not found\n")
log.error(conffile + " not found")
Exiting()
config = ConfigParser.ConfigParser()
config = configparser.ConfigParser()
try:
config.read(conffile)
except:
exit("\nError: Check " + conffile + " for proper [noaacap] section heading\n")
log.error("Check " + conffile + " for proper [noaacap] section heading")
Exiting()
try:
myTZ = config.get('noaacap', 'myTZ')
except:
exit("\nError: Check " + conffile + " for proper myTZ value in [noaacap] section\n")
log.error("Check " + conffile + " for proper myTZ value in [noaacap] section")
Exiting()
try:
myZone = config.get('noaacap', 'myZone')
except:
exit("\nError: Check " + conffile + " for proper myZone value in [noaacap] section\n")
log.error("Check " + conffile + " for proper myZone value in [noaacap] section")
Exiting()
url = 'https://alerts.weather.gov/cap/wwaatmget.php?x=' + myZone + '&y=0'
r = requests.get(url)
if r.status_code != 200:
log.error(str(r.status_code) + " " + url)
Exiting()
soup = BeautifulSoup(r.text, 'xml')
entries = soup.find_all('entry')
count = len(entries)
dbfile = '/dev/shm/noaacap.db'
ppmap = '/usr/local/share/noaacap/ppmap.db'
sg = {"W":"WARN ","A":"WATCH","Y":"ADVIS","S":"STMNT","F":"4CAST",
"O":"OUTLK","N":"SYNOP"}
# Define functions used in the for loop
def aprstime(timestr,TZ):
local = pytz.timezone (TZ)
naive = datetime.datetime.strptime(timestr, "%Y-%m-%dT%H:%M:%S")
@ -107,22 +142,6 @@ def parsezcs(zcs):
zonelist.add(prefix + zone)
return zonelist
sg = {"W":"WARN ","A":"WATCH","Y":"ADVIS","S":"STMNT","F":"4CAST",
"O":"OUTLK","N":"SYNOP"}
url = 'https://alerts.weather.gov/cap/wwaatmget.php?x=' + myZone + '&y=0'
try:
r = requests.get(url)
except:
exit('\n')
soup = BeautifulSoup(r.text, 'xml')
entries = soup.find_all('entry')
count = len(entries)
dbfile = '/dev/shm/noaacap.db'
ppmap = '/usr/local/share/noaacap/ppmap.db'
hit = 0
for i in range(0, count):
@ -132,10 +151,12 @@ for i in range(0, count):
break
else:
if i == 0:
alerts = bsddb.hashopen(dbfile,'c')
pp = bsddb.hashopen(ppmap,'r')
alerts = db.DB()
alerts.open(dbfile, None, db.DB_HASH, db.DB_CREATE)
pp = db.DB()
pp.open(ppmap, None, db.DB_HASH, db.DB_RDONLY)
updated = str(entries[i].updated.string)
updated = entries[i].updated.string
if (entries[i].status.string == "Actual"):
@ -144,15 +165,16 @@ for i in range(0, count):
try:
ProductClass, Action, Office, Phenomena, Significance, ETN, \
EventBegin, EventEnd = vtecparse(VTEC['VTEC'].string)
if (ProductClass <> "/O"): #Loop if not operational
if (ProductClass != "/O"): #Loop if not operational
continue
except:
continue #Loop if error parsing P-VTEC
id = str(Office + Phenomena + Significance + ETN)
id = bytes(str(Office + Phenomena + Significance + ETN), 'utf-8')
if alerts.has_key(id):
if alerts[id] == updated:
if alerts[id].decode('utf-8') == updated:
log.debug(id.decode('utf-8') + " " + updated + " found")
continue
alerts[id] = updated
@ -176,10 +198,10 @@ for i in range(0, count):
t = t + chr(s+61)
# Pull specific alert to get compressed UGC zones
try:
rs = requests.get(entries[i].id.string)
except:
exit('\n')
rs = requests.get(entries[i].id.string)
if rs.status_code != 200:
log.error(str(rs.status_code) + " " + rs)
Exiting()
soup2 = BeautifulSoup(rs.text, 'xml')
parms = soup2.find_all('parameter')
@ -188,19 +210,22 @@ for i in range(0, count):
if parms[j].valueName.string == 'UGC':
zcs = parms[j].value.string
type = pp[str(Phenomena)]
event = sg[Significance]
type = pp[bytes(Phenomena, 'utf-8')].decode('utf-8')
if Action == "CAN":
event = "CANCL"
else:
event = sg[Significance]
hit = 1
message = exputc + "z," + type + "," + zcs
log.info("Msg: " + message)
# Make sure message does not exceed 67 chars. If it
# does, trim it. Also be certain that myZone is included
# included in the trimmed zcs.
n = 0
while len(message) > 67:
n = zcs.rfind('-')
zcs = zcs[0:n]
@ -209,10 +234,15 @@ for i in range(0, count):
zcs = myZone + "-" + zcs
message = exputc + "z," + type + "," + zcs
if n > 0:
log.info("Truncated Msg: " + message)
line = "{" + t + "00"
print ":NWS_" + event + ":" + message + line
print(":NWS_" + event + ":" + message + line)
break
if (hit == 0):
print
print()
log.info("Exiting")

View File

@ -1,5 +1,10 @@
noaacap changelog
##
Version: 0.6
Release: September 15, 2017
Converted to Python3
Added systemd journal support for logging and debugging
##
Version: 0.5
Release: August 31, 2017
Bug fix for long messages to ensure myZone is included

View File

@ -1,10 +1,10 @@
This software is written in python 2.7 and has been tested with aprx 2.9.x.
This software is written in python 3.4 and has been tested with aprx 2.9.x.
If you are running a version < 2.9.0 you should first update aprx. The current
release may be found at http://thelifeofkenneth.com/aprx/debs/.
Once you are running aprx >= 2.9, install noaacap:
Install via sudo dpkg -i noaacap-0.5.deb. Then, to satisfy the dependencies,
Install via sudo dpkg -i noaacap-0.6.deb. Then, to satisfy the dependencies,
run sudo apt-get -f install.
CONFIGURATION
@ -18,10 +18,16 @@ cycle-size 2m
beacon via WIDE2-1 \
srccall N0CALL-13 \
timeout 20 \
exec /usr/local/bin/noaacap.py
</beacon>
The timeout was needed on my older and slower single core Raspberry Pi Model B.
The aprx default timeout is 10 seconds and the timeout may not be needed on a
RPi 2 or newer. If you need lots of "BEACON EXEC abnormal close" messages in
aprx.log, then you likely need to add the timeout.
The program will check for a new alert or update every 2 minutes, but only
send if there is a change.
@ -45,4 +51,4 @@ k2dls@k2dls.net with the callsign-SSID of your APRS station that is sending
weather alerts via this program.
Dan Srebnick, K2DLS
08/19/2017
09/13/2017

BIN
packages/noaacap-0.6.deb Normal file

Binary file not shown.