Skip to content

Commit 6054a38

Browse files
author
Bastian Schroll
authoredApr 16, 2020
Merge pull request #443 from Schrolli91/release_2_5
Release BW 2.5
2 parents ca26f1d + b9c6744 commit 6054a38

File tree

10 files changed

+878
-533
lines changed

10 files changed

+878
-533
lines changed
 

‎CHANGELOG.md

+14-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,25 @@
11
# Changelog
22

3+
### __[v2.5]__ - 16.04.2020
4+
##### Added
5+
- Divera-Plugin: Plugin zum Ansteuern der Divera-Api. [#415](https://github.com/Schrolli91/BOSWatch/pull/415)
6+
- GPIO-Control: Plugin zum Ansteuern der GPIO Pins. [#438](https://github.com/Schrolli91/BOSWatch/pull/438)
7+
##### Changed
8+
- MySQL-Plugin: Index für die RIC Adresse hinzugefügt [#411](https://github.com/Schrolli91/BOSWatch/issues/411)
9+
- MySQL-Plugin: INSERT Befehl für MySQL 8.x angepasst, Spaltennamen escaped [#410](https://github.com/Schrolli91/BOSWatch/issues/410)
10+
- Pushover-Plugin: Konfigurationsmöglichkeit für den Sound [#418](https://github.com/Schrolli91/BOSWatch/issues/418)
11+
##### Fixed
12+
- Description-List: Buchstaben in FMS-Kennungen werden nun erkannt und zugelassen [#409](https://github.com/Schrolli91/BOSWatch/issues/409)
13+
- MySQL-Plugin: Volle UTF-8 Kompatibilität für Datenbankstruktur, Verbindung und Darstellung im WebUI [#398](https://github.com/Schrolli91/BOSWatch/issues/398)
14+
315

416
### __[v2.4.3]__ - 22.09.2019
517
##### Added
618
- Telegram-Plugin: In der generierten Übersichtkarte wird eine Anfahrtsroute integriert. Der Abfahrtsort ist konfiguierbar. [#382](https://github.com/Schrolli91/BOSWatch/pull/382)
719
- Hue-Plugin: Geräte die mit einer Hue bridge verbunden sind können aus BOSWatch ein- und ausgeschaltet werden. [#394](https://github.com/Schrolli91/BOSWatch/issues/394)
820
##### Changed
9-
- FFAgent Plugin: zusätzliches OrderedDict "alarmHeadersOrdered" implementiert um das HTTP Header Ordering sicherzustellen. Zusätzlich den HTTP Request mittels Session implementiert um das Header Ordering zu bewahren. Zusätzliches Debug Logging für die Header implementiert. [#356] (https://github.com/Schrolli91/BOSWatch/issues/356)
10-
- POC-Decoder: Im POC-Text wird nach einem RegEx, welcher Koordinaten enthält, gesucht. Werden diese gefunden, so stehen zwei neu befüllte Data-Felder Lon bzw Lat zur Verfügung.
21+
- FFAgent Plugin: zusätzliches OrderedDict "alarmHeadersOrdered" implementiert um das HTTP Header Ordering sicherzustellen. Zusätzlich den HTTP Request mittels Session implementiert um das Header Ordering zu bewahren. Zusätzliches Debug Logging für die Header implementiert. [#356](https://github.com/Schrolli91/BOSWatch/issues/356)
22+
- POC-Decoder: Im POC-Text wird nach einem RegEx, welcher Koordinaten enthält, gesucht. Werden diese gefunden, so stehen zwei neu befüllte Data-Felder Lon bzw Lat zur Verfügung. [#405](https://github.com/Schrolli91/BOSWatch/pull/405)
1123
##### Fixed
1224
- Asynchrone Alarme: Bei asynchroner Verarbeitung von schnell aufeinander folgenden Alarmen, wurde der Inhalt der Objekte typ, freq und data bereits vor dem Abschluss der Verarbeitung eines Alarms wieder überschrieben. Ergebnis hiervon war die Vermischung von RICs und Texten unterschiedlicher Alarme. Lösung über copy.deepcopy() [#394](https://github.com/Schrolli91/BOSWatch/issues/394)
1325
- POC-Decoder: Bug wegen nicht zugeweisener Variable 'has_geo' [#410](https://github.com/Schrolli91/BOSWatch/issues/413) [HOTFIX]

‎config/config.template.ini

+565-513
Large diffs are not rendered by default.

‎exampleAddOns/simpleWeb/mysql.class.php

+4
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ function __construct($host, $user, $password, $database, $show_error = 1)
3535
$this->error("Datenbank nicht gefunden!", mysqli_error($this->conn));
3636
return false;
3737
}
38+
39+
/* Set character set for database connection to utf8mb4 */
40+
mysqli_query($this->conn, "SET NAMES 'utf8mb4'");
41+
3842
return true;
3943
}
4044

‎includes/descriptionList.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def loadCSV(typ, idField):
4343
for row in reader:
4444
logging.debug(row)
4545
# only import rows with an integer as id, allow subrics though
46-
if re.match("^[0-9]+[A-D]?$", row[idField], re.IGNORECASE):
46+
if re.match("^[0-9A-F]+$", row[idField], re.IGNORECASE):
4747
try:
4848
resultList[row[idField].lower()] = stringConverter.convertToUTF8(row['description'])
4949
except:
@@ -102,7 +102,7 @@ def getDescription(typ, data):
102102
103103
@return: description as string
104104
"""
105-
resultStr = data;
105+
resultStr = data
106106
logging.debug("look up description lists")
107107
try:
108108
if typ == "FMS":

‎includes/globalVars.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
"""
1010

1111
# version info
12-
versionNr = "2.4.3"
12+
versionNr = "2.5"
1313
branch = "master"
14-
buildDate = "22.09.2019"
14+
buildDate = "16.04.2020"
1515

1616
# Global variables
1717
config = 0

‎plugins/Divera/Divera.py

+153
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
#!/usr/bin/python
2+
# -*- coding: UTF-8 -*-
3+
4+
"""
5+
Divera-Plugin to send FMS-, ZVEI- and POCSAG - messages to Divera
6+
@author: Marco Grosjohann
7+
@requires: Divera-Configuration has to be set in the config.ini
8+
"""
9+
10+
import logging # Global logger
11+
import httplib # for the HTTP request
12+
import urllib
13+
from includes import globalVars # Global variables
14+
15+
# from includes.helper import timeHandler
16+
from includes.helper import configHandler
17+
from includes.helper import wildcardHandler
18+
19+
20+
##
21+
#
22+
# onLoad (init) function of plugin
23+
# will be called one time by the pluginLoader on start
24+
#
25+
def onLoad():
26+
"""
27+
While loading the plugins by pluginLoader.loadPlugins()
28+
this onLoad() routine is called one time for initialize the plugin
29+
@requires: nothing
30+
@return: nothing
31+
"""
32+
# nothing to do for this plugin
33+
return
34+
35+
36+
##
37+
#
38+
# Main function of Divera-plugin
39+
# will be called by the alarmHandler
40+
#
41+
def run(typ, freq, data):
42+
"""
43+
This function is the implementation of the Divera-Plugin.
44+
It will send the data to Divera API
45+
@type typ: string (FMS|ZVEI|POC)
46+
@param typ: Typ of the dataset
47+
@type data: map of data (structure see readme.md in plugin folder)
48+
@param data: Contains the parameter
49+
@type freq: string
50+
@keyword freq: frequency of the SDR Stick
51+
@requires: Divera-Configuration has to be set in the config.ini
52+
@return: nothing
53+
"""
54+
try:
55+
if configHandler.checkConfig("Divera"): # read and debug the config
56+
57+
if typ == "FMS":
58+
#
59+
# building message for FMS
60+
#
61+
text = globalVars.config.get("Divera", "fms_text")
62+
title = globalVars.config.get("Divera", "fms_title")
63+
priority = globalVars.config.get("Divera", "fms_prio")
64+
65+
elif typ == "ZVEI":
66+
#
67+
# building message for ZVEI
68+
#
69+
text = globalVars.config.get("Divera", "zvei_text")
70+
title = globalVars.config.get("Divera", "zvei_title")
71+
priority = globalVars.config.get("Divera","zvei_std_prio")
72+
73+
elif typ == "POC":
74+
#
75+
# building message for POC
76+
#
77+
if data["function"] == '1':
78+
priority = globalVars.config.get("Divera", "SubA")
79+
elif data["function"] == '2':
80+
priority = globalVars.config.get("Divera", "SubB")
81+
elif data["function"] == '3':
82+
priority = globalVars.config.get("Divera", "SubC")
83+
elif data["function"] == '4':
84+
priority = globalVars.config.get("Divera", "SubD")
85+
else:
86+
priority = ''
87+
88+
text = globalVars.config.get("Divera", "poc_text")
89+
title = globalVars.config.get("Divera", "poc_title")
90+
91+
else:
92+
logging.warning("Invalid type: %s", typ)
93+
return
94+
95+
try:
96+
#
97+
# Divera-Request
98+
#
99+
logging.debug("send Divera for %s", typ)
100+
101+
# replace the wildcards
102+
text = wildcardHandler.replaceWildcards(text, data)
103+
title = wildcardHandler.replaceWildcards(title, data)
104+
105+
# Logging data to send
106+
logging.debug("Title : %s", title)
107+
logging.debug("Text : %s", text)
108+
logging.debug("Priority: %s", priority)
109+
110+
# check priority value
111+
if (priority != 'false') and (priority != 'true'):
112+
logging.info("No Priority set for type '%s'! Skipping Divera-Alarm!", typ)
113+
return
114+
115+
# start the connection
116+
conn = httplib.HTTPSConnection("www.divera247.com:443")
117+
conn.request("GET", "/api/alarm",
118+
urllib.urlencode({
119+
"accesskey": globalVars.config.get("Divera", "accesskey"),
120+
"title": title,
121+
"text": text,
122+
"priority": priority,
123+
}))
124+
125+
except:
126+
logging.error("cannot send Divera request")
127+
logging.debug("cannot send Divera request", exc_info=True)
128+
return
129+
130+
try:
131+
#
132+
# check Divera-Response
133+
#
134+
response = conn.getresponse()
135+
if str(response.status) == "200": # Check Divera Response and print a Log or Error
136+
logging.debug("Divera response: %s - %s", str(response.status), str(response.reason))
137+
else:
138+
logging.warning("Divera response: %s - %s", str(response.status), str(response.reason))
139+
except: # otherwise
140+
logging.error("cannot get Divera response")
141+
logging.debug("cannot get Divera response", exc_info=True)
142+
return
143+
144+
finally:
145+
logging.debug("close Divera-Connection")
146+
try:
147+
request.close()
148+
except:
149+
pass
150+
151+
except:
152+
logging.error("unknown error")
153+
logging.debug("unknown error", exc_info=True)

‎plugins/MySQL/MySQL.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ def run(typ,freq,data):
9191
# Connect to MySQL
9292
#
9393
logging.debug("connect to MySQL")
94-
connection = mysql.connector.connect(host = globalVars.config.get("MySQL","dbserver"), port = globalVars.config.get("MySQL","dbport"), user = globalVars.config.get("MySQL","dbuser"), passwd = globalVars.config.get("MySQL","dbpassword"), db = globalVars.config.get("MySQL","database"), charset='utf8')
94+
connection = mysql.connector.connect(host = globalVars.config.get("MySQL","dbserver"), port = globalVars.config.get("MySQL","dbport"), user = globalVars.config.get("MySQL","dbuser"), passwd = globalVars.config.get("MySQL","dbpassword"), db = globalVars.config.get("MySQL","database"), charset='utf8mb4')
9595
cursor = connection.cursor()
9696
except:
9797
logging.error("cannot connect to MySQL")
@@ -104,21 +104,21 @@ def run(typ,freq,data):
104104
logging.debug("Insert %s", typ)
105105

106106
if typ == "FMS":
107-
cursor.execute("INSERT INTO "+globalVars.config.get("MySQL","tableFMS")+" (time, fms, status, direction, directionText, tsi, description) VALUES (FROM_UNIXTIME(%s),%s,%s,%s,%s,%s,%s)", (data["timestamp"], data["fms"], data["status"], data["direction"], data["directionText"], data["tsi"], data["description"]))
107+
cursor.execute("INSERT INTO "+globalVars.config.get("MySQL","tableFMS")+" (`time`, `fms`, `status`, `direction`, `directionText`, `tsi`, `description`) VALUES (FROM_UNIXTIME(%s),%s,%s,%s,%s,%s,%s)", (data["timestamp"], data["fms"], data["status"], data["direction"], data["directionText"], data["tsi"], data["description"]))
108108

109109
elif typ == "ZVEI":
110-
cursor.execute("INSERT INTO "+globalVars.config.get("MySQL","tableZVEI")+" (time, zvei, description) VALUES (FROM_UNIXTIME(%s),%s,%s)", (data["timestamp"], data["zvei"], data["description"]))
110+
cursor.execute("INSERT INTO "+globalVars.config.get("MySQL","tableZVEI")+" (`time`, `zvei`, `description`) VALUES (FROM_UNIXTIME(%s),%s,%s)", (data["timestamp"], data["zvei"], data["description"]))
111111

112112
elif typ == "POC":
113113
if isSignal(data["ric"]):
114114
if globalVars.config.getint("POC","netIdent_history"):
115-
cursor.execute("INSERT INTO "+globalVars.config.get("MySQL","tableSIG")+" (time,ric) VALUES (NOW(), '"+data["ric"]+"');")
115+
cursor.execute("INSERT INTO "+globalVars.config.get("MySQL","tableSIG")+" (`time`,`ric`) VALUES (NOW(), '"+data["ric"]+"');")
116116
else:
117117
cursor.execute("UPDATE "+globalVars.config.get("MySQL","tableSIG")+" SET time = NOW() WHERE ric = '"+data["ric"]+"';")
118118
if cursor.rowcount == 0:
119-
cursor.execute("INSERT INTO "+globalVars.config.get("MySQL","tableSIG")+" (time,ric) VALUES (NOW(), '"+data["ric"]+"');")
119+
cursor.execute("INSERT INTO "+globalVars.config.get("MySQL","tableSIG")+" (`time`,`ric`) VALUES (NOW(), '"+data["ric"]+"');")
120120
else:
121-
cursor.execute("INSERT INTO "+globalVars.config.get("MySQL","tablePOC")+" (time, ric, function, functionChar, msg, bitrate, description) VALUES (FROM_UNIXTIME(%s),%s,%s,%s,%s,%s,%s)", (data["timestamp"], data["ric"], data["function"], data["functionChar"], data["msg"], data["bitrate"], data["description"]))
121+
cursor.execute("INSERT INTO "+globalVars.config.get("MySQL","tablePOC")+" (`time`, `ric`, `function`, `functionChar`, `msg`, `bitrate`, `description`) VALUES (FROM_UNIXTIME(%s),%s,%s,%s,%s,%s,%s)", (data["timestamp"], data["ric"], data["function"], data["functionChar"], data["msg"], data["bitrate"], data["description"]))
122122

123123
else:
124124
logging.warning("Invalid Typ: %s", typ)

‎plugins/MySQL/boswatch.sql

+9-8
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,16 @@ SET time_zone = "+00:00";
1717
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
1818
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
1919
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
20-
/*!40101 SET NAMES utf8 */;
20+
/*!40101 SET NAMES utf8mb4 */;
2121

2222
-- --------------------------------------------------------
2323

2424
--
2525
-- Datenbank anlegen `boswatch`
2626
--
2727

28-
CREATE DATABASE IF NOT EXISTS boswatch;
29-
USE boswatch;
28+
CREATE DATABASE IF NOT EXISTS 'boswatch' DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
29+
USE 'boswatch';
3030

3131
-- --------------------------------------------------------
3232

@@ -53,7 +53,7 @@ CREATE TABLE IF NOT EXISTS `bos_fms` (
5353
`tsi` VARCHAR(3) NOT NULL,
5454
`description` TEXT NOT NULL,
5555
PRIMARY KEY (`ID`)
56-
) ENGINE=MYISAM DEFAULT CHARSET=UTF8 AUTO_INCREMENT=1;
56+
) ENGINE=MYISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci AUTO_INCREMENT=1;
5757

5858
-- --------------------------------------------------------
5959

@@ -70,8 +70,9 @@ CREATE TABLE IF NOT EXISTS `bos_pocsag` (
7070
`msg` TEXT NOT NULL,
7171
`bitrate` INT(4) NOT NULL,
7272
`description` TEXT NOT NULL,
73-
PRIMARY KEY (`ID`)
74-
) ENGINE=MYISAM DEFAULT CHARSET=UTF8 AUTO_INCREMENT=1;
73+
PRIMARY KEY (`ID`),
74+
KEY `POCSAG_RIC_IDX` (`ric`)
75+
) ENGINE=MYISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci AUTO_INCREMENT=1;
7576

7677
-- rename old columns including little error-prevention
7778
#ALTER IGNORE TABLE `bos_pocsag` change `funktion` `function` INT(1);
@@ -89,7 +90,7 @@ CREATE TABLE IF NOT EXISTS `bos_zvei` (
8990
`zvei` VARCHAR(5) NOT NULL DEFAULT '0',
9091
`description` TEXT NOT NULL,
9192
PRIMARY KEY (`ID`)
92-
) ENGINE=MYISAM DEFAULT CHARSET=UTF8 AUTO_INCREMENT=1;
93+
) ENGINE=MYISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci AUTO_INCREMENT=1;
9394

9495
-- --------------------------------------------------------
9596

@@ -102,7 +103,7 @@ CREATE TABLE IF NOT EXISTS `bos_signal` (
102103
`time` DATETIME NOT NULL,
103104
`ric` VARCHAR(7) NOT NULL DEFAULT '0',
104105
PRIMARY KEY (`ID`)
105-
) ENGINE=MYISAM DEFAULT CHARSET=UTF8 AUTO_INCREMENT=1;
106+
) ENGINE=MYISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci AUTO_INCREMENT=1;
106107

107108

108109
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;

‎plugins/Pushover/Pushover.py

+5
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,10 @@ def run(typ, freq, data):
128128
# replace the wildcards
129129
message = wildcardHandler.replaceWildcards(message, data)
130130
title = wildcardHandler.replaceWildcards(title, data)
131+
sound = globalVars.config.get("Pushover", "sound")
132+
# set Default-Sound
133+
if not sound:
134+
sound = "pushover"
131135

132136
# start the connection
133137
conn = httplib.HTTPSConnection("api.pushover.net:443")
@@ -138,6 +142,7 @@ def run(typ, freq, data):
138142
"message": message,
139143
"html": globalVars.config.get("Pushover", "html"),
140144
"title": title,
145+
"sound": sound,
141146
"priority": priority,
142147
"retry": globalVars.config.get("Pushover", "retry"),
143148
"expire": globalVars.config.get("Pushover", "expire")

‎plugins/gpiocontrol/gpiocontrol.py

+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#!/usr/bin/python
2+
# -*- coding: UTF-8 -*-
3+
4+
"""
5+
6+
@author: KS
7+
8+
@requires: none
9+
"""
10+
11+
# Imports
12+
13+
import RPi.GPIO as GPIO
14+
import time
15+
import threading
16+
17+
import logging # Global logger
18+
from includes import globalVars # Global variables
19+
20+
# Helper function, uncomment to use
21+
from includes.helper import timeHandler
22+
from includes.helper import wildcardHandler
23+
from includes.helper import configHandler
24+
25+
##
26+
#
27+
# onLoad (init) function of plugin
28+
# will be called one time by the pluginLoader on start
29+
#
30+
def onLoad():
31+
"""
32+
While loading the plugins by pluginLoader.loadPlugins()
33+
this onLoad() routine is called one time for initialize the plugin
34+
35+
@requires: nothing
36+
37+
@return: nothing
38+
@exception: Exception if init has an fatal error so that the plugin couldn't work
39+
40+
"""
41+
global GPIOPIN
42+
global waitTime
43+
44+
GPIOPIN = globalVars.config.getint("gpiocontrol","pin")
45+
waitTime = globalVars.config.getint("gpiocontrol","triggertime")
46+
47+
GPIO.setmode(GPIO.BCM)
48+
GPIO.setwarnings(False)
49+
GPIO.setup(GPIOPIN, GPIO.OUT)
50+
51+
#GPIO schalten beim START
52+
#GPIO.output(GPIOPIN, GPIO.LOW)
53+
#time.sleep(1)
54+
55+
GPIO.output(GPIOPIN, GPIO.HIGH)
56+
57+
return
58+
59+
#
60+
#
61+
# Main function of plugin
62+
# will be called by the alarmHandler
63+
#
64+
def run(typ,freq,data):
65+
"""
66+
@type typ: string (FMS|ZVEI|POC)
67+
@param typ: Typ of the dataset
68+
@type data: map of data (structure see readme.md in plugin folder)
69+
@param data: Contains the parameter for dispatch
70+
@type freq: string
71+
@keyword freq: frequency of the SDR Stick
72+
73+
@requires: If necessary the configuration hast to be set in the config.ini.
74+
75+
@return: nothing
76+
@exception: nothing, make sure this function will never thrown an exception
77+
"""
78+
try:
79+
if configHandler.checkConfig("gpiocontrol"): #read and debug the config (let empty if no config used)
80+
81+
logging.debug(globalVars.config.get("gpiocontrol", "pin"))
82+
logging.debug(globalVars.config.get("gpiocontrol", "triggertime"))
83+
84+
########## User Plugin CODE ##########
85+
if typ == "FMS":
86+
th = threading.Thread(target = trigger)
87+
th.start()
88+
#logging.warning("%s not supported", typ)
89+
elif typ == "ZVEI":
90+
th = threading.Thread(target = trigger)
91+
th.start()
92+
#logging.warning("%s not supported", typ)
93+
elif typ == "POC":
94+
if globalVars.config.get("gpiocontrol", "activerics") == "":
95+
th = threading.Thread(target = trigger)
96+
th.start()
97+
else
98+
if data["ric"] in globalVars.config.get("gpiocontrol", "activerics"):
99+
th = threading.Thread(target = trigger)
100+
th.start()
101+
else:
102+
logging.info("Ric not in activerics")
103+
else:
104+
logging.warning("Invalid Typ: %s", typ)
105+
########## User Plugin CODE ##########
106+
107+
except:
108+
logging.error("unknown error")
109+
logging.debug("unknown error", exc_info=True)
110+
111+
def trigger():
112+
GPIO.output(GPIOPIN, GPIO.LOW)
113+
logging.info("GPIOPIN %s angeschaltet", GPIOPIN)
114+
time.sleep(waitTime)
115+
GPIO.output(GPIOPIN, GPIO.HIGH)
116+
logging.info("GPIOPIN %s ausgeschaltet", GPIOPIN)
117+
118+
return

0 commit comments

Comments
 (0)
Please sign in to comment.