diff --git a/CHANGELOG.md b/CHANGELOG.md index 61b9383..ebdc85b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,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. [#394](https://github.com/Schrolli91/BOSWatch/issues/394) ##### Changed ##### 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() [#394](https://github.com/Schrolli91/BOSWatch/issues/394) ##### Security diff --git a/config/config.template.ini b/config/config.template.ini index e2800ed..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 = @@ -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 # diff --git a/includes/alarmHandler.py b/includes/alarmHandler.py index 13627fc..95b6cf0 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 # copy objects to avoid issues if the objects will be changed by the plugin's during runtime and during asynch/threaded processing ## # @@ -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) @@ -80,7 +81,7 @@ 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 @@ -88,7 +89,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(typ, freq, deepcopy(data)) logging.debug("return from: %s", pluginName) except: # call next plugin, if one has thrown an exception diff --git a/plugins/hue/hue.py b/plugins/hue/hue.py new file mode 100644 index 0000000..87f74bb --- /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)