Skip to content

Commit

Permalink
Phase 5
Browse files Browse the repository at this point in the history
Signed-off-by: Scott Rushworth <[email protected]>
  • Loading branch information
Scott Rushworth committed May 11, 2019
1 parent 8f6d101 commit d193c0c
Show file tree
Hide file tree
Showing 10 changed files with 89 additions and 94 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
python module which can be used to send SMS messages via the Clickatell HTTP/S API
Interface on https://api.clickatell.com/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
from core.rules import rule
from core.triggers import when
from core.utils import getItemValue, getLastUpdate
import configuration
from configuration import weatherStationUploader_configuration, customDateTimeFormats

wu_second_count = 10 # Loop counter

Expand Down Expand Up @@ -65,18 +65,18 @@ def getTheSensor(lbl, never_assume_dead=False, getHighest=False, getLowest=False
# When "getHighest" argument is set to True, the sensor name with the highest value is picked.
# When "getlowest" argument is set to True, the sensor name with the lowest value is picked.

sensor_dead_after_mins = configuration.wunderground['sensor_dead_after_mins'] # The time after which a sensor is presumed to be dead
sensor_dead_after_mins = weatherStationUploader_configuration['sensor_dead_after_mins'] # The time after which a sensor is presumed to be dead

def isSensorAlive(sName):
if getLastUpdate(ir.getItem(sName)).isAfter(DateTime.now().minusMinutes(sensor_dead_after_mins)):
return True
else:
weatherStationUploader.log.warn("Sensor device {} has not reported since: {}".format(sName, format_date(getLastUpdate(ir.getItem(sName)), configuration.customDateTimeFormats['dateTime'])))
weatherStationUploader.log.warn("Sensor device {} has not reported since: {}".format(sName, format_date(getLastUpdate(ir.getItem(sName)), customDateTimeFormats['dateTime'])))
return False

sensorName = None
if lbl in configuration.wunderground['sensors'] and configuration.wunderground['sensors'][lbl] is not None:
tSens = configuration.wunderground['sensors'][lbl]
if lbl in weatherStationUploader_configuration['sensors'] and weatherStationUploader_configuration['sensors'][lbl] is not None:
tSens = weatherStationUploader_configuration['sensors'][lbl]
if isinstance(tSens, list):
_highestValue = 0
_lowestValue = 999999999
Expand Down Expand Up @@ -109,11 +109,11 @@ def isSensorAlive(sName):
@rule("Weather station uploader")
@when("Time cron 0/10 * * * * ?")
def weatherStationUploader(event):
weatherStationUploader.log.setLevel(configuration.wunderground['logLevel'])
weatherStationUploader.log.setLevel(weatherStationUploader_configuration['logLevel'])
global wu_second_count
if (not configuration.wunderground['stationdata']['weather_upload']) \
or (configuration.wunderground['stationdata']['weather_upload'] and wu_second_count%configuration.wunderground['stationdata']['upload_frequency_seconds'] == 0):
if configuration.wunderground['stationdata']['weather_upload']:
if (not weatherStationUploader_configuration['stationdata']['weather_upload']) \
or (weatherStationUploader_configuration['stationdata']['weather_upload'] and wu_second_count%weatherStationUploader_configuration['stationdata']['upload_frequency_seconds'] == 0):
if weatherStationUploader_configuration['stationdata']['weather_upload']:
weatherStationUploader.log.debug('Uploading data to Weather Underground')
else:
weatherStationUploader.log.debug('No data to will be upladed to Weather Underground')
Expand Down Expand Up @@ -216,15 +216,15 @@ def weatherStationUploader(event):

cmd = 'curl -s -G "' + WU_URL + '" ' \
+ '--data-urlencode "action=updateraw" ' \
+ ('--data-urlencode "realtime=1" ' if configuration.wunderground['stationdata']['rapid_fire_mode'] else '') \
+ ('--data-urlencode "rtfreq='+str(configuration.wunderground['stationdata']['upload_frequency_seconds'])+'" ' if configuration.wunderground['stationdata']['rapid_fire_mode'] else '') \
+ '--data-urlencode "ID='+configuration.wunderground['stationdata']['station_id']+'" ' \
+ '--data-urlencode "PASSWORD='+configuration.wunderground['stationdata']['station_key']+'" ' \
+ ('--data-urlencode "realtime=1" ' if weatherStationUploader_configuration['stationdata']['rapid_fire_mode'] else '') \
+ ('--data-urlencode "rtfreq='+str(weatherStationUploader_configuration['stationdata']['upload_frequency_seconds'])+'" ' if weatherStationUploader_configuration['stationdata']['rapid_fire_mode'] else '') \
+ '--data-urlencode "ID='+weatherStationUploader_configuration['stationdata']['station_id']+'" ' \
+ '--data-urlencode "PASSWORD='+weatherStationUploader_configuration['stationdata']['station_key']+'" ' \
+ '--data-urlencode "dateutc='+dateutc+'" ' \
+ '--data-urlencode "softwaretype=openHAB" '
weatherStationUploader.log.debug("")

if configuration.wunderground['stationdata']['weather_upload']:
if weatherStationUploader_configuration['stationdata']['weather_upload']:
weatherStationUploader.log.debug("Below is the weather data that we will send:")
else:
weatherStationUploader.log.debug("Below is the weather data that we would send (if weather_upload was enabled):")
Expand Down Expand Up @@ -286,13 +286,13 @@ def weatherStationUploader(event):
cmd += ' 1>/dev/null 2>&1 &'
weatherStationUploader.log.debug("")

if configuration.wunderground['stationdata']['weather_upload']:
if weatherStationUploader_configuration['stationdata']['weather_upload']:
weatherStationUploader.log.debug("WeatherUpload version {}, performing an upload. (second count is: {})".format(__version__, wu_second_count))
weatherStationUploader.log.debug("cmd: {}".format(cmd))
os.system(cmd)
else:
weatherStationUploader.log.debug("WeatherUpload version {}, skipping upload. (second count is: {})".format(__version__, wu_second_count))

if (wu_second_count%configuration.wunderground['stationdata']['upload_frequency_seconds'] == 0):
if (wu_second_count%weatherStationUploader_configuration['stationdata']['upload_frequency_seconds'] == 0):
wu_second_count = 0
wu_second_count = wu_second_count + 10 # Corresponding to CronTrigger(EVERY_10_SECONDS)
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# The first sensor that has been reporting data since the time out defined in sensor_dead_after_mins
# will be used. If you don't have a certain sensor type, just put None (Don't put None inside a list)
# Not mandatory. You may remove.
wunderground = {
weatherStationUploader_configuration = {
'logLevel': DEBUG,
'stationdata': {
"weather_upload": False, # Set to True to actually upload anything
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
from community.idealarm import ideAlarm

@rule("ideAlarm main rule", description="Make ideAlarm trigger on item changes. Do not alter.")
@ideAlarm.getTriggers()
def ideAlarmMainRule(event):
@ideAlarm.get_triggers()
def ideAlarm_main_rule(event):
ideAlarm.execute(event)
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,27 @@
from core.jsr223 import scope
from core.date import format_date
from core.log import logging, LOG_PREFIX
from core.utils import isActive, getItemValue, postUpdateCheckFirst, sendCommandCheckFirst, kw
from core.utils import getItemValue, postUpdateCheckFirst, sendCommandCheckFirst, kw
from core.actions import PersistenceExtensions
from configuration import customDateTimeFormats
from configuration import idealarm_configuration, customDateTimeFormats
from personal.idealarm import custom

log = logging.getLogger(LOG_PREFIX + '.ideAlarm')
log = logging.getLogger(LOG_PREFIX + '.community.ideAlarm')
ZONESTATUS = {'NORMAL': 0, 'ALERT': 1, 'ERROR': 2, 'TRIPPED': 3, 'ARMING': 4}
ARMINGMODE = {'DISARMED': 0, 'ARMED_HOME': 1, 'ARMED_AWAY': 2}

def isActive(item):
'''
Tries to determine if a device is active (tripped) from the perspective of an alarm system.
A door lock is special in the way that when it's locked its contacts are OPEN, hence
the value needs to be inverted for the alarm system to determine if it's 'active'
'''
active = False
if item.state in [scope.ON, scope.OPEN]:
active = True
active = not active if configuration.customGroupNames['lockDevice'] in item.groupNames else active
return active

class IdeAlarmError(Exception):
'''
Base class for IdeAlarm errors
Expand Down Expand Up @@ -69,7 +81,6 @@ def getLastUpdate(self):
self.log.info(u"Could not retrieve persistence data for sensor: {}".format(self.name.decode('utf8')))
return lastUpdate


class IdeAlarmZone(object):
'''
Alarm Zone Object
Expand Down Expand Up @@ -347,19 +358,18 @@ def __init__(self):
self.__version__ = '4.0.0'
self.__version_info__ = tuple([ int(num) for num in self.__version__.split('.')])
self.log = logging.getLogger("{}.IdeAlarm V{}".format(LOG_PREFIX, self.__version__))
from configuration import idealarm as _cfg

self.alarmTestMode = _cfg['ALARM_TEST_MODE']
self.loggingLevel = _cfg['LOGGING_LEVEL']
self.alarmTestMode = idealarm_configuration['ALARM_TEST_MODE']
self.loggingLevel = idealarm_configuration['LOGGING_LEVEL']
self.log.setLevel(self.loggingLevel)
self.log.debug('ideAlarm configuration was reloaded')
self.nagIntervalMinutes = _cfg['NAG_INTERVAL_MINUTES']
self.nagIntervalMinutes = idealarm_configuration['NAG_INTERVAL_MINUTES']
self.timeCreated = DateTime.now()

self.alarmZones = []
for i in range(len(_cfg['ALARM_ZONES'])):
for i in range(len(idealarm_configuration['ALARM_ZONES'])):
zoneNumber = i+1
self.alarmZones.append(IdeAlarmZone(self, zoneNumber, _cfg['ALARM_ZONES'][i]))
self.alarmZones.append(IdeAlarmZone(self, zoneNumber, idealarm_configuration['ALARM_ZONES'][i]))

for alarmZone in self.alarmZones:
alarmZone.getNagSensors()
Expand Down Expand Up @@ -436,12 +446,12 @@ def getAlertingZonesCount(self):
if self.getZoneStatus(i) == ZONESTATUS['ALERT']: alertingZones += 1
return alertingZones

def getTriggers(self):
def get_triggers(self):
'''
Wraps the function with core.triggers.when for all triggers that shall trigger ideAlarm.
'''
from core.triggers import when
def generatedTriggers(function):
def generated_triggers(function):
for item in self.getSensors():
when("Item {} changed".format(item))(function) # TODO: Check if this works for items with accented characters in the name
for i in range(len(self.alarmZones)):
Expand All @@ -452,7 +462,7 @@ def generatedTriggers(function):
when("Item Z{}_Nag_Timer received command OFF".format(i + 1))(function)
when("Item Z{}_Alert_Max_Timer received command OFF".format(i + 1))(function)
return function
return generatedTriggers
return generated_triggers

def execute(self, event):
'''
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
# -*- coding: utf-8 -*-
'''
This is an example configuration file for ideAlarm.
You should copy the contents of this file abd paste into your ordinary
You should copy the contents of this file and paste into your ordinary
openhab2-jython configuration file e.g. automation\lib\python\configuration.py
'''
# The following import statements should be in your configuration
from core.jsr223 import scope

# You can define functions to determine if a sensor is enabled or not.
# The following functions takes 2 arguments, events and log.
# The function shall return a boolean.
# If you are not going to use functions to determine if a sensor is enabled or not,
# you dont have to include it in your configuration file.
def d5Enabled(events, log):
def d5Enabled():
'''
Door 5 sensor shall only be enabled if an Internet connection is available.
'''
return (scope.itemRegistry.getItem('Network_Internet').state == scope.ON)

# ideAlarm Configuration example for two zones.

idealarm = {
idealarm_configuration = {
'ALARM_TEST_MODE': True,
'LOGGING_LEVEL': 'DEBUG',
'NAG_INTERVAL_MINUTES': 6,
Expand All @@ -34,7 +32,7 @@ idealarm = {
{'name': 'Door_1_Lock', 'sensorClass': 'A', 'nag': True, 'nagTimeoutMins': 4, 'armWarn': True, 'enabled': True},
{'name': 'Door_4_Lock', 'sensorClass': 'A', 'nag': True, 'nagTimeoutMins': 4, 'armWarn': True, 'enabled': False},
{'name': 'Door_4', 'sensorClass': 'A', 'nag': True, 'nagTimeoutMins': 4, 'armWarn': True, 'enabled': True},
{'name': 'Door_5_Lock', 'sensorClass': 'A', 'nag': True, 'nagTimeoutMins': 10, 'armWarn': True, 'enabled': d5Enabled}
{'name': 'Door_5_Lock', 'sensorClass': 'A', 'nag': True, 'nagTimeoutMins': 10, 'armWarn': True, 'enabled': d5Enabled()}
],
'armAwayToggleSwitch': 'Toggle_Z1_Armed_Away',
'armHomeToggleSwitch': 'Toggle_Z1_Armed_Home',
Expand Down Expand Up @@ -71,6 +69,9 @@ customDateTimeFormats = {
'time': 'HH:mm:ss' # Time only
}

customGroupNames = {
'lockDevice': 'G_Lock', # Group Item name that you've assigned to all your door lock devices
}

# Pushover related.
# Uncomment if you are going to use Pushover notifications https://pushover.net
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
# -*- coding: utf-8 -*-
'''
Custom ideAlarm functions library.
Edit this file to suit your needs.
'''
from core.log import logging, LOG_PREFIX
from core.utils import kw

log = logging.getLogger(LOG_PREFIX + '.ideAlarm.custom')
log = logging.getLogger(LOG_PREFIX + '.personal.ideAlarm.custom')

ZONESTATUS = {'NORMAL': 0, 'ALERT': 1, 'ERROR': 2, 'TRIPPED': 3, 'ARMING': 4}
ARMINGMODE = {'DISARMED': 0, 'ARMED_HOME': 1, 'ARMED_AWAY': 2}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
'''
custom_verbose_example.py

Expand All @@ -20,7 +19,7 @@
from community.clickatell.sendsms import sms
#from community import autoremote

log = logging.getLogger(LOG_PREFIX + '.ideAlarm.custom')
log = logging.getLogger(LOG_PREFIX + '.personal.ideAlarm.custom')

ZONESTATUS = {'NORMAL': 0, 'ALERT': 1, 'ERROR': 2, 'TRIPPED': 3, 'ARMING': 4}
ARMINGMODE = {'DISARMED': 0, 'ARMED_HOME': 1, 'ARMED_AWAY': 2}
Expand Down
Loading

0 comments on commit d193c0c

Please sign in to comment.