Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
Bastian Schroll committed Sep 22, 2019
2 parents 65dd9b4 + dd82fe8 commit 7a8afb1
Show file tree
Hide file tree
Showing 7 changed files with 220 additions and 12 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
# Changelog


### __[v2.4.3]__ - 22.09.1991
##### Added
- Telegram-Plugin: In der generierten Übersichtkarte wird eine Anfahrtsroute integriert. Der Abfahrtsort ist konfiguierbar. [#382](https://github.com/Schrolli91/BOSWatch/pull/382)
- 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)
##### Changed
- 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)
- 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.
##### Fixed
- 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)


### __[v2.4.2]__ - 11.03.2019
##### Added
- Telegram-Plugin: In der generierten Übersichtkarte wird eine Anfahrtsroute integriert. Der Abfahrtsort ist konfiguierbar. [#382](https://github.com/Schrolli91/BOSWatch/pull/382)
Expand Down
30 changes: 29 additions & 1 deletion config/config.template.ini
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,13 @@ netIdent_ric = 0174760, 1398098
# you can hold one entry per netIdent_ric [0] or the whole history [1]
netIdent_history = 0

# With some message, coordinates can be sent to determine the destination
# Do you want to enable this feature? (0 - off | 1 - on)
geo_enable = 0
# If a RIC contains coordinates, specify the regex used to decode them
geo_format = #C(\d{2})(\d{5}),(\d{2})(\d{5})#
geo_order = LON, lon, LAT, lat


[multicastAlarm]
# Configure multicastAlarm if your POCSAG network uses an optimized transmission scheme for alarms with more than one RIC (often found in Swissphone networks).
Expand All @@ -131,7 +138,7 @@ multicastAlarm_ignore_time = 15
# multicastAlarm delimiter RIC (usually used as a starting point for a alarm sequence). Needs to be empty if multicastAlarms are interrupted by normal alarms.
multicastAlarm_delimiter_ric =

# multicastAlarm RIC that is used to send the text message
# multicastAlarm RIC (one or more, separated by comma) used to send the text message
multicastAlarm_ric =


Expand Down Expand Up @@ -167,6 +174,7 @@ FFAgent = 0
Pushover = 0
Telegram = 0
yowsup = 0
hue = 0

# for developing - template-module
template = 0
Expand Down Expand Up @@ -434,6 +442,26 @@ zvei_message = %DATE% %TIME%: %ZVEI%
#Wildcards can be used, see end of the file!
poc_message = %MSG%

[hue]
# For API access please read https://www.developers.meethue.com/documentation/getting-started (registration required)
# or https://www.google.com/search?q=philips+hue+how+to+get+api+key
# IP address of the hue bridge
bridgeip =

# the numeric ID of the device (only one device supported)
deviceid =

# the authentication string used to access the bridge
apikey =

# Timing parameters for switching on/off
# Every on/off cycle adds delay to BOSwatch if it operates in synchronous mode. Consider to configure "processAlarmAsync = 1" to activate asynchronous operation in BOSwatch if you switch on/off multiple times.
# If a light bulb is connected, you can keep it blinking for a while
repeat = 2
timeon = 2
timeoff = 1
# configure 0 to keep the switch on for infinite time or configure >=1 to keep it for the value in seconds to on, before switching to off.
keepon = 60

#####################
##### Not ready yet #
Expand Down
7 changes: 4 additions & 3 deletions includes/alarmHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import time # timestamp

from includes import globalVars # Global variables
from copy import deepcopy # copy objects to avoid issues if the objects will be changed by the plugin's during runtime and during asynch/threaded processing

##
#
Expand All @@ -40,7 +41,7 @@ def processAlarmHandler(typ, freq, data):
logging.debug("starting processAlarm async")
try:
from threading import Thread
Thread(target=processAlarm, args=(typ, freq, data)).start()
Thread(target=processAlarm, args=(typ, freq, deepcopy(data))).start()
except:
logging.error("Error in starting alarm processing async")
logging.debug("Error in starting alarm processing async", exc_info=True)
Expand Down Expand Up @@ -80,15 +81,15 @@ def processAlarm(typ, freq, data):
if regexFilter.checkFilters(typ, data, pluginName, freq):
logging.debug("call Plugin: %s", pluginName)
try:
plugin.run(typ, freq, data)
plugin.run(typ, freq, deepcopy(data))
logging.debug("return from: %s", pluginName)
except:
# call next plugin, if one has thrown an exception
pass
else: # RegEX filter off - call plugin directly
logging.debug("call Plugin: %s", pluginName)
try:
plugin.run(typ, freq, data)
plugin.run(typ, freq, deepcopy(data))
logging.debug("return from: %s", pluginName)
except:
# call next plugin, if one has thrown an exception
Expand Down
31 changes: 28 additions & 3 deletions includes/decoders/poc.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,16 +123,41 @@ def decode(freq, decoded):
logging.debug("POCSAG Bitrate: %s", bitrate)

if "Alpha:" in decoded: #check if there is a text message
poc_text = decoded.split('Alpha: ')[1].strip().replace('<NUL><NUL>','').replace('<NUL>','').replace('<NUL','').replace('< NUL>','').replace('<EOT>','').strip()
poc_text = decoded.split('Alpha: ')[1].strip().replace('<NUL><NUL>','').replace('<NUL>','').replace('<NUL','').replace('< NUL>','').replace('<EOT>','').strip()
if globalVars.config.getint("POC","geo_enable"):
try:
logging.debug("Using %s to find geo-tag in %s", globalVars.config.get("POC","geo_format"),poc_text)
m = re.search(globalVars.config.get("POC","geo_format"),poc_text)
if m:
logging.debug("Found geo-tag in message, parsing...")
has_geo = True
geo_order = globalVars.config.get("POC","geo_order").split(',')
if geo_order[0].lower == "lon":
lat = m.group(1) + "." + m.group(2)
lon = m.group(3) + "." + m.group(4)
else:
lon = m.group(1) + "." + m.group(2)
lat = m.group(3) + "." + m.group(4)
logging.debug("Finished parsing geo; lon: %s, lat: %s", lon, lat)
else:
logging.debug("No geo-tag found")
has_geo = False
except:
has_geo = False
logging.error("Exception parsing geo-information",exc_info=true)
else:
has_geo = False
else:
poc_text = ""

if re.search("[0-9]{7}", poc_id) and re.search("[1-4]{1}", poc_sub): #if POC is valid
if isAllowed(poc_id):

# check for double alarm
if doubleFilter.checkID("POC", poc_id+poc_sub, poc_text):
data = {"ric":poc_id, "function":poc_sub, "msg":poc_text, "bitrate":bitrate, "description":poc_id}
data = {"ric":poc_id, "function":poc_sub, "msg":poc_text, "bitrate":bitrate, "description":poc_id, "has_geo":has_geo}
if has_geo == True:
data["lon"] = lon
data["lat"] = lat
# Add function as character a-d to dataset
data["functionChar"] = data["function"].replace("1", "a").replace("2", "b").replace("3", "c").replace("4", "d")

Expand Down
4 changes: 2 additions & 2 deletions includes/globalVars.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
"""

# version info
versionNr = "2.4.2"
versionNr = "2.4.3"
branch = "master"
buildDate = "11.03.2019"
buildDate = "22.09.2019"

# Global variables
config = 0
Expand Down
27 changes: 24 additions & 3 deletions plugins/FFAgent/FFAgent.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import hmac, hashlib
import json, requests

from collections import OrderedDict

from includes import globalVars # Global variables

#from includes.helper import timeHandler
Expand Down Expand Up @@ -123,21 +125,40 @@ def run(typ,freq,data):
}

alarmData = json.dumps(alarmData)

logging.debug(alarmData)

alarmHeaders = {
"Content-Type": "application/json",
"webApiToken": webApiToken,
"accessToken": accessToken,
"selectiveCallCode": selectiveCallCode,
"hmac": hmac.new(webApiKey, webApiToken + selectiveCallCode + accessToken + alarmData, digestmod=hashlib.sha256).hexdigest()
}

logging.debug(alarmHeaders)

alarmHeadersOrdered=OrderedDict()
alarmHeadersOrdered['webApiToken']=webApiToken
alarmHeadersOrdered['accessToken']=accessToken
alarmHeadersOrdered['selectiveCallCode']=selectiveCallCode
alarmHeadersOrdered['hmac']=hmac.new(webApiKey, webApiToken + selectiveCallCode + accessToken + alarmData, digestmod=hashlib.sha256).hexdigest()

logging.debug(alarmHeadersOrdered)

if globalVars.config.get("FFAgent", "live") == "1":
r = requests.post(url, data=alarmData, headers=alarmHeaders, verify=serverCertFile, cert=(clientCertFile, clientCertPass))
s = requests.Session()
s.headers = OrderedDict([('Content-Type', 'application/json')])
logging.debug(s.headers)
r = s.post(url, data=alarmData, headers=alarmHeadersOrdered, verify=serverCertFile, cert=(clientCertFile, clientCertPass))

else:
r = requests.post(url, data=alarmData, headers=alarmHeaders, verify=serverCertFile)
s = requests.Session()
s.headers = OrderedDict([('Content-Type', 'application/json')])
logging.debug(s.headers)
r = s.post(url, data=alarmData, headers=alarmHeadersOrdered, verify=serverCertFile)

logging.debug(r.request.headers)

except:
logging.error("cannot send FFAgent request")
Expand Down
122 changes: 122 additions & 0 deletions plugins/hue/hue.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#!/usr/bin/python
# -*- coding: UTF-8 -*-

"""
Plugin to control Philips hue lights and switches
@author: Fabian Kessler
@requires: none
"""

#
# Imports
#
import logging # Global logger
from includes import globalVars # Global variables
import json
import requests
import time

# Helper function, uncomment to use
#from includes.helper import timeHandler
#from includes.helper import wildcardHandler
from includes.helper import configHandler

##
#
# onLoad (init) function of plugin
# will be called one time by the pluginLoader on start
#
def onLoad():
"""
While loading the plugins by pluginLoader.loadPlugins()
this onLoad() routine is called one time for initialize the plugin
@requires: nothing
@return: nothing
@exception: Exception if init has an fatal error so that the plugin couldn't work
"""
try:
########## User onLoad CODE ##########
pass
########## User onLoad CODE ##########
except:
logging.error("unknown error")
logging.debug("unknown error", exc_info=True)
raise

##
#
# Main function of plugin
# will be called by the alarmHandler
#
def run(typ,freq,data):
"""
This function is the implementation of the Plugin.
If necessary the configuration hast to be set in the config.ini.
@type typ: string (FMS|ZVEI|POC)
@param typ: Typ of the dataset
@type data: map of data (structure see readme.md in plugin folder)
@param data: Contains the parameter for dispatch
@type freq: string
@keyword freq: frequency of the SDR Stick
@requires: If necessary the configuration hast to be set in the config.ini.
@return: nothing
@exception: nothing, make sure this function will never thrown an exception
"""
try:
if configHandler.checkConfig("hue"): #read and debug the config
#for debugging
"""logging.debug(globalVars.config.get("hue", "bridgeip"))
logging.debug(globalVars.config.get("hue", "deviceid"))
logging.debug(globalVars.config.get("hue", "apikey"))
logging.debug(globalVars.config.getint("hue", "repeat"))
logging.debug(globalVars.config.getint("hue", "timeon"))
logging.debug(globalVars.config.getint("hue", "timeoff"))
logging.debug(globalVars.config.getint("hue", "keepon"))"""

########## User Plugin CODE ##########
if typ == "FMS":
logging.warning("%s not supported", typ)
elif typ == "ZVEI":
logging.warning("%s not supported", typ)
elif typ == "POC":
#logging.warning("%s not supported", typ)
logging.debug("POC received")
bridgeip = globalVars.config.get("hue", "bridgeip")
deviceid = globalVars.config.get("hue", "deviceid")
apikey = globalVars.config.get("hue", "apikey")
repeat = globalVars.config.getint("hue", "repeat")
timeon = globalVars.config.getint("hue", "timeon")
timeoff = globalVars.config.getint("hue", "timeoff")
keepon = globalVars.config.getint("hue", "keepon")
data_on = '{"on":true}'
data_off = '{"on":false}'
url = "http://" + bridgeip + "/api/" + apikey + "/lights/" + deviceid + "/state"
logging.debug("hue REST API URL: %s", url)

#blinking
for _ in xrange(repeat):
requests.put(url, data=data_on)
logging.debug("on for %s seconds", timeon)
time.sleep(timeon)
requests.put(url, data=data_off)
logging.debug("off for %s seconds", timeoff)
time.sleep(timeoff)
if keepon > 0:
logging.debug("switch to on and wait for keepon to expire")
requests.put(url, data=data_on)
logging.debug("keep on for %s seconds", keepon)
time.sleep(keepon)
requests.put(url, data=data_off)
else:
logging.debug("switch to on and exit plugin")
requests.put(url, data=data_on)
else:
logging.warning("Invalid Typ: %s", typ)
########## User Plugin CODE ##########

except:
logging.error("unknown error")
logging.debug("unknown error", exc_info=True)

0 comments on commit 7a8afb1

Please sign in to comment.