def invoke_callback(channel): """Invoke Callback""" try: HUB_LOGGER.info("Impulse Callback from pin %s", channel) # Only one impulse per pin allowed, # so we can lookup the impulse from pin number # Establish database Connection conn = hub_connect.get_connection() # Create cursor - needed for any database operation cur = hub_connect.get_cursor(conn) select_sql = 'SELECT * from "Impulse" WHERE "BCMPinNumber" = %s' cur.execute(select_sql, (channel, )) # Read result impulse = cur.fetchone() if cur.rowcount == 1: HUB_LOGGER.info("Impulse Button Detected for pin %s", channel) create_event(conn, cur, impulse) except Exception: HUB_LOGGER.error("Unable to invoke impulse callback") etype = sys.exc_info()[0] value = sys.exc_info()[1] trace = sys.exc_info()[2] line = trace.tb_lineno HUB_LOGGER.error("%s %s %s", etype, value, line)
def toggle_actuator(state, agent, method_params, email_recipient, text_recipient): """this action is simply to set the actuator state to the negation of the incoming state""" try: actuator_id = int(method_params[0]) # need to ignore incoming state and re-read the actuator state! # Establish database Connection conn = hub_connect.get_connection() # Create cursor - needed for any database operation cur = hub_connect.get_cursor(conn) select_sql = 'SELECT * from "Actuator" WHERE "ActuatorID" = %s' # Read result cur.execute(select_sql, (actuator_id, )) actuator = cur.fetchone() if actuator is not None: cur_val = actuator.get('CurrentValue') HUB_LOGGER.info( "In toggle_actuator reading %s current value as %s", actuator_id, cur_val) state = (float(cur_val) > 0.0) HUB_LOGGER.info("In toggle_actuator reading state as %s", state) new_state = not state # toggle HUB_LOGGER.info("In toggle_actuator using new state %s", new_state) do_action(new_state, actuator_id, agent, 'toggle_actuator', email_recipient, text_recipient) else: new_state = False return new_state except Exception: HUB_LOGGER.error("Unable to Toggle Actuator %s %s %s", sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2].tb_lineno)
def truncate_samples(): """Truncate Samples""" try: # Establish database Connection conn = hub_connect.get_connection() # Create cursor - needed for any database operation cur = hub_connect.get_cursor(conn) delete_sql1 = ('DELETE FROM "Sample" ' 'WHERE "Timestamp" < (NOW() - INTERVAL \'1 WEEK\')') HUB_LOGGER.info("Truncating Sample Table...") cur.execute(delete_sql1) conn.commit() delete_sql2 = ('DELETE FROM "EventQueue" ' 'WHERE "Timestamp" < (NOW() - INTERVAL \'1 WEEK\')') HUB_LOGGER.info("Truncating EventQueue Table...") cur.execute(delete_sql2) conn.commit() # Close communication with the database cur.close() conn.close() except Exception: HUB_LOGGER.error("Unable to truncate samples") etype = sys.exc_info()[0] value = sys.exc_info()[1] trace = sys.exc_info()[2] line = trace.tb_lineno HUB_LOGGER.error("%s %s %s", etype, value, line)
def arp_detected(mac): """ARP packet detected""" HUB_LOGGER.debug("ARP Request Detected : %s", mac) # Query Impulse for this mac address # Establish database Connection conn = hub_connect.get_connection() # Create cursor - needed for any database operation cur = hub_connect.get_cursor(conn) select_sql = 'SELECT * from "Impulse" WHERE "MacAddress" = %s' cur.execute(select_sql, (mac, )) # Read result impulse = cur.fetchone() if cur.rowcount == 1: HUB_LOGGER.info("Dash ARP Request Detected for %s", mac) create_event(conn, cur, impulse)
def process_actuators(): """Process Actuators""" try: # Establish database Connection conn = hub_connect.get_connection() # Create cursor - needed for any database operation cur = hub_connect.get_cursor(conn) select_sql = 'SELECT * from "vwActuators" ORDER BY "ActuatorID"' cur.execute(select_sql) # Read results into python list actuators = cur.fetchall() # uncomment to debug # print_actuators(actuators) HUB_LOGGER.debug("Processing actuators...") for actuator in actuators: actuator_id = int(actuator.get('ActuatorID')) HUB_LOGGER.debug("Processing actuator %d", actuator_id) cur_val = float(actuator.get('CurrentValue')) # Use computed method for actuators for this version # Actuator Function may include additional parameters, # so pass them as list # e.g. remote.130.5 # {function.subnet_host.id} => function([subnet_host, id]) actuator_function = actuator.get('ActuatorFunction') if actuator_function is not None: method_params = actuator_function.split('.') HUB_LOGGER.debug("method_params: %s", method_params) method_to_call = method_params.pop(0) HUB_LOGGER.debug("method_to_call: %s", method_to_call) method_exists = hasattr(actuator_helpers, method_to_call) HUB_LOGGER.debug("%s method exists: %s", method_to_call, method_exists) if method_exists: # method_to_call = 'SimpleOnOff' method = getattr(actuator_helpers, method_to_call) result = method(cur_val, method_params) HUB_LOGGER.debug("%f => %s", cur_val, result) else: HUB_LOGGER.error("Missing Function: %s", method_to_call) else: HUB_LOGGER.error( "Missing Function Specification for Actuator: %s", actuator_id) # Close communication with the database cur.close() conn.close() except Exception: HUB_LOGGER.error("Unable to process actuators %s %s %s", sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2].tb_lineno)
def do_action(state, actuator_id, agent, action, email_recipient, text_recipient): """Do the Action""" HUB_LOGGER.info("In do_action incoming action alerts %s %s %s %s %s", state, actuator_id, action, email_recipient, text_recipient) try: # Establish database Connection conn = hub_connect.get_connection() # Create cursor - needed for any database operation cur = hub_connect.get_cursor(conn) # Update the Actuator only if Current Value has changed! upd_sql = ('UPDATE "Actuator" SET "CurrentValue" = %s,' ' "LastUpdated" = CURRENT_TIMESTAMP,' ' "UpdatedBy" = %s WHERE' ' "ActuatorID" = %s AND "IsInAuto" = \'Y\'' ' AND "CurrentValue" <> %s;') cur.execute(upd_sql, (state * 1, agent, actuator_id, state * 1)) rows_affected = cur.rowcount HUB_LOGGER.debug("Update Actuator qry: [ %s ] Rows Affected: %s", cur.query, rows_affected) conn.commit() if rows_affected > 0: # Look-up the Actuator's Name for the alerts read_sql = ('SELECT "ActuatorName" FROM "Actuator" ' 'WHERE "ActuatorID" = %s') # Read result cur.execute(read_sql, (actuator_id, )) actuator = cur.fetchone() act_name = 'UnNamed Actuator' if actuator is not None: act_name = actuator.get('ActuatorName') # Send Alerts? if ((email_recipient is not None and email_recipient != '') or (text_recipient is not None and text_recipient != '')): send_alert(state, agent, action, email_recipient, text_recipient, act_name) # Close communication with the database cur.close() conn.close() except Exception: HUB_LOGGER.error("Unable to Do Action %s %s %s", sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2].tb_lineno) return True
def process_samples(): """Process Samples""" try: # Establish database Connection conn = hub_connect.get_connection() # Create cursor - needed for any database operation cur = hub_connect.get_cursor(conn) select_sql = 'SELECT * from "vwSampleDefs" ORDER BY "SampleDefID"' cur.execute(select_sql) # Read results into python list sample_defs = cur.fetchall() print_sample_defs(sample_defs) HUB_LOGGER.info("Processing Sample Definitions") for sample_def in sample_defs: sensor_id = int(sample_def.get('SensorEntryID')) cur_val = float(sample_def.get('CurrentValue')) method_to_call = sample_def.get('SampleTypeName').lower() HUB_LOGGER.debug("method_to_call: %s", method_to_call) max_val = sample_def.get('MaxValue') min_val = sample_def.get('MinValue') HUB_LOGGER.debug( "max: %s[%s] min: %s[%s]", max_val, type(max_val), min_val, type(min_val) ) method = getattr(sampler_helpers, method_to_call) result = method(sensor_id, cur_val) HUB_LOGGER.debug( "%s => %s[%s]", cur_val, result, type(result) ) # Insert Database with sample value? if ((result is not None) and (max_val is None or result <= max_val) and (min_val is None or result >= min_val)): cur.execute( 'INSERT INTO "Sample" ("SensorEntryID","Value")' ' VALUES (%s, %s);', (sensor_id, result)) else: HUB_LOGGER.warning( "Excluding invalid sample from database %s", result) conn.commit() # Close communication with the database cur.close() conn.close() except Exception: HUB_LOGGER.error("Unable to process samples") HUB_LOGGER.error("%s %s %s", sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2].tb_lineno)
def process_rules_from_event_queue(source_type='*', source_id=-1): """Process Rules from Event Queue""" HUB_LOGGER.debug("Processing Rules From Event Queue for %s %s...", source_type, source_id) try: # Establish database Connection conn = hub_connect.get_connection() # Create cursor - needed for any database operation cur = hub_connect.get_cursor(conn) event_queue_sql = "SELECT * from \"vwEventRuleActions\"" if source_type != '*' and source_id != -1: # Request for specific rules to be processed event_queue_sql += (' WHERE "SourceType" = \'' + source_type + '\' AND "SourceID" = ' + str(source_id)) HUB_LOGGER.info("Processing Rules From Event Queue sql: %s", event_queue_sql) cur.execute(event_queue_sql) # Read results into python list event_rule_actions = cur.fetchall() era_count = cur.rowcount if era_count > 0: HUB_LOGGER.info("Processing %s event rule actions...", era_count) for event_rule_action in event_rule_actions: process_event_rule_action(conn, cur, event_rule_action) # Close communication with the database cur.close() conn.close() except Exception: HUB_LOGGER.error("Unable to process rules") etype = sys.exc_info()[0] value = sys.exc_info()[1] trace = sys.exc_info()[2] line = trace.tb_lineno HUB_LOGGER.error("%s %s %s", etype, value, line)
def process_timers(): """Processes Timers""" try: # Establish database Connection conn = hub_connect.get_connection() # Create cursor - needed for any database operation cur = hub_connect.get_cursor(conn) # Process Actuator Timers select_sql = ('SELECT "ActuatorEntryID", "OnForMins", "OffForMins" ' 'FROM "Actuator"') cur.execute(select_sql) # Read results into python list actuators = cur.fetchall() HUB_LOGGER.info("Processing Actuator Timers") for act in actuators: act_id = int(act.get('ActuatorEntryID')) cur_on_val = int(act.get('OnForMins')) if cur_on_val >= 0: HUB_LOGGER.debug("Incrementing Actuator On Timer %s", act_id) cur_on_val = cur_on_val + 1 # Update Database with current value cur.execute( 'UPDATE "Actuator" SET "OnForMins" = %s ' 'WHERE "ActuatorEntryID" = %s;', (cur_on_val, act_id)) conn.commit() else: HUB_LOGGER.debug("Ignoring Actuator On Timer %s - Disabled", act_id) cur_off_val = int(act.get('OffForMins')) if cur_off_val >= 0: HUB_LOGGER.debug("Incrementing Actuator Off Timer %s", act_id) cur_off_val = cur_off_val + 1 # Update Database with current value cur.execute( 'UPDATE "Actuator" SET "OffForMins" = %s ' 'WHERE "ActuatorEntryID" = %s;', (cur_off_val, act_id)) conn.commit() else: HUB_LOGGER.debug("Ignoring Actuator Off Timer %s - Disabled", act_id) # Close communication with the database cur.close() conn.close() except Exception: HUB_LOGGER.error("Unable to process timers") etype = sys.exc_info()[0] value = sys.exc_info()[1] trace = sys.exc_info()[2] line = trace.tb_lineno HUB_LOGGER.error("%s %s %s", etype, value, line)
def check_complex_conditions(): """Check Complex Conditions""" try: # Establish database Connection conn = hub_connect.get_connection() # Create cursor - needed for any database operation cur = hub_connect.get_cursor(conn) select_sql = ('SELECT * from "vwComplexConditions" ' 'ORDER BY "ConditionID"') cur.execute(select_sql) # Read results into python list conditions = cur.fetchall() print_complex_conditions(conditions) select_sql = ('SELECT "SensorID", "CurrentValue" FROM "Sensor" ' 'ORDER BY "SensorID" DESC') cur.execute(select_sql) # Read results into python list cur_vals = cur.fetchall() select_sql = ('SELECT "ActuatorID", "OnForMins", "OffForMins" ' 'FROM "Actuator"') cur.execute(select_sql) # Read results into python list cur_timers = cur.fetchall() HUB_LOGGER.info("Processing Complex Conditions...") for condition in conditions: HUB_LOGGER.info("-------------------------------") check_condition(conn, cur, cur_vals, cur_timers, condition) # Close communication with the database cur.close() conn.close() except Exception: HUB_LOGGER.error("Unable to process complex conditions") etype = sys.exc_info()[0] value = sys.exc_info()[1] trace = sys.exc_info()[2] line = trace.tb_lineno HUB_LOGGER.error("%s %s %s", etype, value, line)
def initialise(impulse_pins): """Initialise""" try: HUB_LOGGER.info("Initialising impulses wired to physical buttons...") # Establish database Connection conn = hub_connect.get_connection() # Create cursor - needed for any database operation cur = hub_connect.get_cursor(conn) select_sql = ( 'SELECT * from "Impulse" WHERE "BCMPinNumber" IS NOT NULL' ' ORDER BY "ImpulseID"') cur.execute(select_sql) # Read results into python list impulses = cur.fetchall() print_impulses(impulses) GPIO.setmode(GPIO.BCM) cur_impulse_pins = [] for impulse in impulses: impulse_id = int(impulse.get('ImpulseID')) pin = int(impulse.get('BCMPinNumber')) cur_impulse_pins.append(pin) if pin not in impulse_pins: # Impulse Switch wired from Pin to Ground # Add Pull-Up GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Clear any existing GPIO.remove_event_detect(pin) GPIO.add_event_detect(pin, GPIO.RISING, callback=invoke_callback, bouncetime=2000) # Mark Impulse as Initialised impulse_pins.append(pin) HUB_LOGGER.info("Initialised impulse %s on pin %s", impulse_id, pin) ex_impulse_pins = set(impulse_pins) - set(cur_impulse_pins) for pin in ex_impulse_pins: # Clear any existing GPIO.remove_event_detect(pin) HUB_LOGGER.info("Decommissioned impulse on pin %s", pin) impulse_pins.remove(pin) except Exception: HUB_LOGGER.error("Unable to initialise impulses") etype = sys.exc_info()[0] value = sys.exc_info()[1] trace = sys.exc_info()[2] line = trace.tb_lineno HUB_LOGGER.error("%s %s %s", etype, value, line)
def process_stats(): """Process Statistics""" try: # Establish database Connection conn = hub_connect.get_connection() # Create cursor - needed for any database operation cur = hub_connect.get_cursor(conn) select_sql = ( 'SELECT * from "Sensor" s' ' INNER JOIN "Measurand" m ON s."MeasurandID" = m."MeasurandID"' ' ORDER BY "SensorID"') cur.execute(select_sql) # Read results into python list sensors = cur.fetchall() HUB_LOGGER.info("Processing Stats") for sensor in sensors: sensor_entry_id = int(sensor.get('SensorEntryID')) cur_val = float(sensor.get('CurrentValue')) meas_max_val = sensor.get('MaxValue') meas_min_val = sensor.get('MinValue') if meas_max_val is None or meas_max_val >= cur_val: HUB_LOGGER.info("Processing Max Stats for sensor %s", sensor_entry_id) process_max_min(conn, cur, sensor_entry_id, cur_val, 'Maximum') if meas_min_val is None or meas_min_val <= cur_val: HUB_LOGGER.info("Processing Min Stats for sensor %s", sensor_entry_id) process_max_min(conn, cur, sensor_entry_id, cur_val, 'Minimum') # Close communication with the database cur.close() conn.close() except Exception: HUB_LOGGER.error("Unable to process statistics") etype = sys.exc_info()[0] value = sys.exc_info()[1] trace = sys.exc_info()[2] line = trace.tb_lineno trace = traceback.format_exc() HUB_LOGGER.error("%s %s %s %s", etype, value, line, trace)
def daily_summary(): """Daily Summary""" try: # Establish database Connection conn = hub_connect.get_connection() # Create cursor - needed for any database operation cur = hub_connect.get_cursor(conn) select_sql = 'SELECT * from "vwTodaysMaximums" ORDER BY "SensorID"' cur.execute(select_sql) msg_body = '' msg_tmplt = '* {0} {1} {2} at {3}\r\n' if cur.rowcount > 0: # Read results into python list maximums = cur.fetchall() HUB_LOGGER.info("Processing Daily Maxs") msg_body += ('The following highest values' ' have been recorded today:\r\n\r\n') for maximum in maximums: sensor_title = maximum.get('SensorTitle') val = float(maximum.get('Value')) units = maximum.get('TextUnits') date = datetime.datetime.strftime(maximum.get('Timestamp'), '%H:%M %d/%m/%Y') msg_body += msg_tmplt.format(sensor_title, val, units, date) msg_body += '\r\n' select_sql = "SELECT * from \"vwTodaysMinimums\" ORDER BY \"SensorID\"" cur.execute(select_sql) if cur.rowcount > 0: # Read results into python list minimums = cur.fetchall() HUB_LOGGER.info("Processing Daily Mins") msg_body += ('The following lowest values' ' have been recorded today:\r\n\r\n') for minimum in minimums: sensor_title = minimum.get('SensorTitle') val = float(minimum.get('Value')) units = minimum.get('TextUnits') date = datetime.datetime.strftime(minimum.get('Timestamp'), '%H:%M %d/%m/%Y') msg_body += msg_tmplt.format(sensor_title, val, units, date) if msg_body != '': HUB_LOGGER.info("Processing Daily Summary: %s", msg_body) # Send Email subject = ('Daily Highs and Lows from the Hub ' + datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%d')) email_recip = helpers.get_user_setting('AdminRecipient') helpers.send_email(msg_body, subject, email_recip) except Exception: HUB_LOGGER.error("Unable to process daily summary statistics") HUB_LOGGER.error("%s %s %s", sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2].tb_lineno)
def invoke_callback(channel): """Invoke Callback""" try: HUB_LOGGER.info("Impulse Callback from pin %s", channel) # Only one impulse per pin allowed, # so we can lookup the impulse from pin number # Establish database Connection conn = hub_connect.get_connection() # Create cursor - needed for any database operation cur = hub_connect.get_cursor(conn) select_sql = 'SELECT * from "Impulse" WHERE "BCMPinNumber" = %s' cur.execute(select_sql, (channel, )) # Read results into python list impulses = cur.fetchall() impulse_id = int(impulses[0].get('ImpulseID')) HUB_LOGGER.info("Inserting Impulse Event in Database... %s", impulse_id) ins_sql = ('INSERT INTO "EventQueue" ' '("SourceID", "SourceType", "SourceAgent", "Value")' 'SELECT %s, \'Impulse\', \'Occupant\', 1' 'WHERE (' ' SELECT COUNT(*)' ' FROM "EventQueue"' ' WHERE "SourceID" = %s AND' ' "SourceType" = \'Impulse\'' ' AND "Timestamp" > ' ' current_timestamp - interval \'%s seconds\'' ') = 0;') cur.execute(ins_sql, (impulse_id, impulse_id, LOCKOUT_SECONDS)) conn.commit() HUB_LOGGER.info("Impulse Update Query... %s", cur.query) HUB_LOGGER.info("Updating Impulse Last Updated in Database... %s", impulse_id) cur.execute( 'UPDATE "Impulse" SET "LastUpdated" = CURRENT_TIMESTAMP' ' WHERE "ImpulseID" = %s;', (impulse_id, )) conn.commit() except Exception: HUB_LOGGER.error("Unable to invoke impulse callback") etype = sys.exc_info()[0] value = sys.exc_info()[1] trace = sys.exc_info()[2] line = trace.tb_lineno HUB_LOGGER.error("%s %s %s", etype, value, line)