Tracking LAN Uptime on My ASUS/Merlin Router – Lambda Collect
Posted On December 22, 2017
The introduction and architecture to the LAN uptime system that I have added to my ASUS/Merlin router has been described in a previous post. This post will focus on the Lambda function that collects the data. The code can be found at the end of this post.
This lambda function receives information passed to it from the router via API Gateway. After initializing some variables it reads the last values stored in the DynamoDB table. After that is it able to determine is a notification needs to be sent to the SNS topic and what that notification should be. Lastly it saves the data into the DynamoDB table.
There were really no serious difficulties in this Lambda function.
- The ExpirationEpochSecs DynamoDB attribute is set to a date in the future where DynamoDB will automatically delete the record via the Time to Live mechanism. The format for this time value is the number of seconds elapsed since 12:00:00 AM January 1st, 1970 UTC.
- When reading the DynamoDB table it is important to remember that the last record written may have been written yesterday. So the code needs to check today first. If no records returned, then check yesterday. Both checks look for the latest record by limiting the return set to 1 record and using the reverse of the sort key.
Here is the code.
from time import localtime, strftime, time from json import dumps from boto3.dynamodb.conditions import Key, Attr import boto3 import json print('Loading function') ddb = boto3.resource('dynamodb') sns = boto3.client('sns') def respond(err, res=None): return { 'statusCode': '400' if err else '200', 'body': err.message if err else res } def lambda_handler(event, context): print("Received event: " + dumps(event, indent=2)) # initialize tableName = lan todayid = strftime('%d%m%y', localtime()) timestamp = strftime('%Y%m%d%H%M%S', localtime()) yesterdayid = strftime('%d%m%y', localtime(time() - 86400)) expiration = int(time()) + 2678400 # plus 31 days in seconds error = False # get the new values newwiredalive = int(event['wiredalive']) newwiredhost = event['wiredhost'] newwireless24alive = int(event['wireless24alive']) newwireless24host = event['wireless24host'] newwireless5alive = int(event['wireless5alive']) newwireless5host = event['wireless5host'] fromip = event['X-Forwarded-For'] # read from dynamodb table lan tbl = ddb.Table(tableName) resp = tbl.query (TableName=tableName, Limit=1, ScanIndexForward=False, KeyConditionExpression=Key('DayId').eq(todayid)) if len(resp['Items']) == 0: resp = tbl.query (TableName=tableName, Limit=1, ScanIndexForward=False, KeyConditionExpression=Key('DayId').eq(yesterdayid)) if len(resp['Items']) == 0: oldwiredalive = 1 oldwireless24alive = 1 oldwireless5alive = 1 else: itm=resp['Items'][0] oldwiredalive = int(itm['WiredAliveInd']) oldwireless24alive = int(itm['Wireless24AliveInd']) oldwireless5alive = int(itm['Wireless5AliveInd']) # check for need to notify notif = False msg = '' if newwiredalive != oldwiredalive: notif = True status = 'up' if newwiredalive == 0: status = 'down' msg = 'Wired connection to ' + newwiredhost + ' is ' + status + '. ' if newwireless24alive != oldwireless24alive: notif = True status = 'up' if newwireless24alive == 0: status = 'down' msg = msg + 'Wireless connection to ' + newwireless24host + ' is ' + status + '. ' if newwireless5alive != oldwireless5alive: notif = True status = 'up' if newwireless5alive == 0: status = 'down' msg = msg + 'Wireless connection to ' + newwireless5host + ' is ' + status + '.' if notif == True: sns.publish(TopicArn='arn:aws:sns:<region>:<account#>:<topic>', Message=msg) # write a new record to the table lan tbl.put_item (Item={ 'DayId': todayid, 'CreateTS': timestamp, 'ExpirationEpochSecs': expiration, 'WiredAliveInd': newwiredalive, 'WiredHost': newwiredhost, 'Wireless24AliveInd': newwireless24alive, 'Wireless24Host': newwireless24host, 'Wireless5AliveInd': newwireless5alive, 'Wireless5Host': newwireless5host, 'FromIP': fromip }) return respond(None, msg)