From 1eae3098e06c7dbf03ebea5bb540efb73f76a317 Mon Sep 17 00:00:00 2001 From: f-kessler Date: Sun, 3 Mar 2019 16:13:06 +0100 Subject: [PATCH 01/12] Add hue plugin --- plugins/hue/hue.py | 122 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 plugins/hue/hue.py diff --git a/plugins/hue/hue.py b/plugins/hue/hue.py new file mode 100644 index 0000000..d01647b --- /dev/null +++ b/plugins/hue/hue.py @@ -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) \ No newline at end of file From 04f98f21c4637048d01740df9b8a219ef918e900 Mon Sep 17 00:00:00 2001 From: f-kessler Date: Sun, 3 Mar 2019 16:16:21 +0100 Subject: [PATCH 02/12] fix for #375 https://github.com/Schrolli91/BOSWatch/issues/375 --- includes/alarmHandler.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/includes/alarmHandler.py b/includes/alarmHandler.py index 13627fc..06e144b 100644 --- a/includes/alarmHandler.py +++ b/includes/alarmHandler.py @@ -40,7 +40,11 @@ def processAlarmHandler(typ, freq, data): logging.debug("starting processAlarm async") try: from threading import Thread - Thread(target=processAlarm, args=(typ, freq, data)).start() + from copy import deepcopy + dctyp = deepcopy(typ) + dcfreq = deepcopy(freq) + dcdata = deepcopy(data) + Thread(target=processAlarm, args=(dctyp, dcfreq, dcdata)).start() except: logging.error("Error in starting alarm processing async") logging.debug("Error in starting alarm processing async", exc_info=True) From 94321415f57119f4b4cd415b0f1bc808c483f236 Mon Sep 17 00:00:00 2001 From: f-kessler Date: Sun, 3 Mar 2019 16:34:05 +0100 Subject: [PATCH 03/12] settings for hue added --- config/config.template.ini | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/config/config.template.ini b/config/config.template.ini index e2800ed..f152f0c 100644 --- a/config/config.template.ini +++ b/config/config.template.ini @@ -167,6 +167,7 @@ FFAgent = 0 Pushover = 0 Telegram = 0 yowsup = 0 +hue = 0 # for developing - template-module template = 0 @@ -434,6 +435,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 # From 5fc8f92f4200c37ec070e8e56921c41b20195d59 Mon Sep 17 00:00:00 2001 From: f-kessler Date: Sun, 3 Mar 2019 17:04:28 +0100 Subject: [PATCH 04/12] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 852ef54..5b03037 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,13 @@ ### __[v#.#]__ - date ##### 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. [#393](https://github.com/Schrolli91/BOSWatch/issues/393) ##### Changed - Telegram-Plugin: Aufrufe der Google API erfolgen per SSL und ohne zusätzliche Bibliotheken [#382](https://github.com/Schrolli91/BOSWatch/pull/382) ##### Deprecated ##### Removed ##### 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() [#375](https://github.com/Schrolli91/BOSWatch/issues/375) ##### Security From 6332bd39a1dcb42d8cd64560c9033ee6a209d7c7 Mon Sep 17 00:00:00 2001 From: f-kessler Date: Sun, 3 Mar 2019 17:08:03 +0100 Subject: [PATCH 05/12] description for multicastAlarm RIC updated --- config/config.template.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.template.ini b/config/config.template.ini index f152f0c..04742ca 100644 --- a/config/config.template.ini +++ b/config/config.template.ini @@ -131,7 +131,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 = From a360b1cd8ab472276aab5c594025ee944f4ca548 Mon Sep 17 00:00:00 2001 From: f-kessler Date: Sun, 3 Mar 2019 20:08:44 +0100 Subject: [PATCH 06/12] Update CHANGELOG.md --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b03037..99c4ba8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,13 +4,13 @@ ### __[v#.#]__ - date ##### 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. [#393](https://github.com/Schrolli91/BOSWatch/issues/393) +- 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 - Telegram-Plugin: Aufrufe der Google API erfolgen per SSL und ohne zusätzliche Bibliotheken [#382](https://github.com/Schrolli91/BOSWatch/pull/382) ##### Deprecated ##### Removed ##### 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() [#375](https://github.com/Schrolli91/BOSWatch/issues/375) +- 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) ##### Security From f86aeb914b09cb6ec4f4ea78a9e7d7b33c202861 Mon Sep 17 00:00:00 2001 From: f-kessler Date: Sun, 3 Mar 2019 20:38:43 +0100 Subject: [PATCH 07/12] Update alarmHandler.py --- includes/alarmHandler.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/includes/alarmHandler.py b/includes/alarmHandler.py index 06e144b..38724a8 100644 --- a/includes/alarmHandler.py +++ b/includes/alarmHandler.py @@ -14,6 +14,7 @@ import logging # Global logger import time # timestamp from includes import globalVars # Global variables +from copy import deepcopy ## # @@ -36,20 +37,20 @@ def processAlarmHandler(typ, freq, data): @return: nothing @exception: Exception if starting a Thread failed """ + #copy objects to avoid issues if the objects will be changed by plugin's or during asynch/threaded processing + dctyp = deepcopy(typ) + dcfreq = deepcopy(freq) + dcdata = deepcopy(data) if globalVars.config.getboolean("BOSWatch","processAlarmAsync") == True: logging.debug("starting processAlarm async") try: from threading import Thread - from copy import deepcopy - dctyp = deepcopy(typ) - dcfreq = deepcopy(freq) - dcdata = deepcopy(data) Thread(target=processAlarm, args=(dctyp, dcfreq, dcdata)).start() except: logging.error("Error in starting alarm processing async") logging.debug("Error in starting alarm processing async", exc_info=True) else: - processAlarm(typ, freq, data) + processAlarm(dctyp, dcfreq, dcdata) ## From ea68fabc12e28d634995c6ba4a72c6d1eccf877a Mon Sep 17 00:00:00 2001 From: f-kessler Date: Thu, 14 Mar 2019 11:41:38 +0100 Subject: [PATCH 08/12] logging fixed --- plugins/hue/hue.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/hue/hue.py b/plugins/hue/hue.py index d01647b..87f74bb 100644 --- a/plugins/hue/hue.py +++ b/plugins/hue/hue.py @@ -119,4 +119,4 @@ def run(typ,freq,data): except: logging.error("unknown error") -logging.debug("unknown error", exc_info=True) \ No newline at end of file + logging.debug("unknown error", exc_info=True) From b3e63afc9ce0c34091fa0813da3114d227b6df89 Mon Sep 17 00:00:00 2001 From: f-kessler Date: Thu, 14 Mar 2019 12:02:00 +0100 Subject: [PATCH 09/12] deepcopy of alarm data moved to processAlarm --- includes/alarmHandler.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/includes/alarmHandler.py b/includes/alarmHandler.py index 38724a8..3cff661 100644 --- a/includes/alarmHandler.py +++ b/includes/alarmHandler.py @@ -37,20 +37,16 @@ def processAlarmHandler(typ, freq, data): @return: nothing @exception: Exception if starting a Thread failed """ - #copy objects to avoid issues if the objects will be changed by plugin's or during asynch/threaded processing - dctyp = deepcopy(typ) - dcfreq = deepcopy(freq) - dcdata = deepcopy(data) if globalVars.config.getboolean("BOSWatch","processAlarmAsync") == True: logging.debug("starting processAlarm async") try: from threading import Thread - Thread(target=processAlarm, args=(dctyp, dcfreq, dcdata)).start() + Thread(target=processAlarm, args=(typ, freq, data)).start() except: logging.error("Error in starting alarm processing async") logging.debug("Error in starting alarm processing async", exc_info=True) else: - processAlarm(dctyp, dcfreq, dcdata) + processAlarm(typ, freq, data) ## @@ -77,15 +73,19 @@ def processAlarm(typ, freq, data): logging.debug("[ ALARM ]") # timestamp, to make sure, that all plugins use the same time data['timestamp'] = int(time.time()) + #copy objects to avoid issues if the objects will be changed by the plugin's during runtime or during asynch/threaded processing + dctyp = deepcopy(typ) + dcfreq = deepcopy(freq) + dcdata = deepcopy(data) # Go to all plugins in pluginList for pluginName, plugin in globalVars.pluginList.items(): # if enabled use RegEx-filter if globalVars.config.getint("BOSWatch","useRegExFilter"): from includes import regexFilter - if regexFilter.checkFilters(typ, data, pluginName, freq): + if regexFilter.checkFilters(dctyp, dcdata, pluginName, dcfreq): logging.debug("call Plugin: %s", pluginName) try: - plugin.run(typ, freq, data) + plugin.run(dctyp, dcfreq, dcdata) logging.debug("return from: %s", pluginName) except: # call next plugin, if one has thrown an exception @@ -93,7 +93,7 @@ def processAlarm(typ, freq, data): else: # RegEX filter off - call plugin directly logging.debug("call Plugin: %s", pluginName) try: - plugin.run(typ, freq, data) + plugin.run(dctyp, dcfreq, dcdata) logging.debug("return from: %s", pluginName) except: # call next plugin, if one has thrown an exception From 07a69d5e26514ce06cc9f1ead049e72970e4d0c4 Mon Sep 17 00:00:00 2001 From: f-kessler Date: Thu, 14 Mar 2019 12:04:35 +0100 Subject: [PATCH 10/12] comment updated --- includes/alarmHandler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/alarmHandler.py b/includes/alarmHandler.py index 3cff661..98998e0 100644 --- a/includes/alarmHandler.py +++ b/includes/alarmHandler.py @@ -73,7 +73,7 @@ def processAlarm(typ, freq, data): logging.debug("[ ALARM ]") # timestamp, to make sure, that all plugins use the same time data['timestamp'] = int(time.time()) - #copy objects to avoid issues if the objects will be changed by the plugin's during runtime or during asynch/threaded processing + # copy objects to avoid issues if the objects will be changed by the plugin's during runtime and during asynch/threaded processing dctyp = deepcopy(typ) dcfreq = deepcopy(freq) dcdata = deepcopy(data) From b1170668b216c79716d09e10d8b1269fec157389 Mon Sep 17 00:00:00 2001 From: f-kessler Date: Thu, 14 Mar 2019 12:07:32 +0100 Subject: [PATCH 11/12] moved copy into for loop --- includes/alarmHandler.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/includes/alarmHandler.py b/includes/alarmHandler.py index 98998e0..92a80db 100644 --- a/includes/alarmHandler.py +++ b/includes/alarmHandler.py @@ -73,12 +73,12 @@ def processAlarm(typ, freq, data): logging.debug("[ ALARM ]") # timestamp, to make sure, that all plugins use the same time data['timestamp'] = int(time.time()) - # copy objects to avoid issues if the objects will be changed by the plugin's during runtime and during asynch/threaded processing - dctyp = deepcopy(typ) - dcfreq = deepcopy(freq) - dcdata = deepcopy(data) # Go to all plugins in pluginList for pluginName, plugin in globalVars.pluginList.items(): + # copy objects to avoid issues if the objects will be changed by the plugin's during runtime and during asynch/threaded processing + dctyp = deepcopy(typ) + dcfreq = deepcopy(freq) + dcdata = deepcopy(data) # if enabled use RegEx-filter if globalVars.config.getint("BOSWatch","useRegExFilter"): from includes import regexFilter From af887c2b23ce3b8eab0778c441d43f39b3dcf586 Mon Sep 17 00:00:00 2001 From: f-kessler Date: Thu, 25 Apr 2019 21:35:21 +0200 Subject: [PATCH 12/12] enhancement for deepcopy --- includes/alarmHandler.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/includes/alarmHandler.py b/includes/alarmHandler.py index 92a80db..95b6cf0 100644 --- a/includes/alarmHandler.py +++ b/includes/alarmHandler.py @@ -14,7 +14,7 @@ import logging # Global logger import time # timestamp from includes import globalVars # Global variables -from copy import deepcopy +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 ## # @@ -41,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) @@ -75,17 +75,13 @@ def processAlarm(typ, freq, data): data['timestamp'] = int(time.time()) # Go to all plugins in pluginList for pluginName, plugin in globalVars.pluginList.items(): - # copy objects to avoid issues if the objects will be changed by the plugin's during runtime and during asynch/threaded processing - dctyp = deepcopy(typ) - dcfreq = deepcopy(freq) - dcdata = deepcopy(data) # if enabled use RegEx-filter if globalVars.config.getint("BOSWatch","useRegExFilter"): from includes import regexFilter - if regexFilter.checkFilters(dctyp, dcdata, pluginName, dcfreq): + if regexFilter.checkFilters(typ, data, pluginName, freq): logging.debug("call Plugin: %s", pluginName) try: - plugin.run(dctyp, dcfreq, dcdata) + plugin.run(typ, freq, deepcopy(data)) logging.debug("return from: %s", pluginName) except: # call next plugin, if one has thrown an exception @@ -93,7 +89,7 @@ def processAlarm(typ, freq, data): else: # RegEX filter off - call plugin directly logging.debug("call Plugin: %s", pluginName) try: - plugin.run(dctyp, dcfreq, dcdata) + plugin.run(typ, freq, deepcopy(data)) logging.debug("return from: %s", pluginName) except: # call next plugin, if one has thrown an exception