Scheduling Functionality - alyoshenka/neo GitHub Wiki

As a user, I want to be able to select an operation, then select a time, then have that operation be performed at that time. For example, I could schedule the LED board to print a message saying "Welcome home from school roommates, there is food on the stove please help yourself" at 3pm tomorrow. From a technical perspective, how is this achieved?

  1. Operation and schedule data are input via the Dibiasky web application
  2. This data is formatted into a topic
const publishTopic = 'cmd/neo/schedule/req' // The topic to send this request to
const scheduledOperation = { // The payload to send
    responseTopic: 'cmd/neo/schedule/res', // The topic to send a success/failure message of the scheduling process to
    executeAt: '', // The time for the operation to run
    operationTopic: 'cmd/neo/hubble/req', // The topic to publish the operation to
    operation: { // The operation to run; This is what `neo` will interpret
        responseTopic: 'cmd/neo/hubble/res', // The topic to send a success/failure message of the operation itself
        module: 'neopolitan', // The module operation
        subCommand: 'update', // Additional (optional) data the operation needs
        friendlyName: 'Run Neopolitan Update with Options', // Optional display name
        options: [ say: 'hello world', speed: 'fast', 'wrap': True ], // Additional options, if required by the operation
    }
};
  1. The operation is published to the topic: publish(publishTopic, scheduledOperation);
  2. An IoT Topic Rule receives the payload: Manage -> Message routing -> Rules, selects from it, then invokes a Lambda using the payload selected using SQL
    • TimeDataToLambda: SELECT * FROM '/cmd/neo/schedule/req' -> ReceiveScheduleFunction
  3. The Lambda Function processes the payload
    1. The payload is validated and a response is generated
      1. The presence of an executeAt field is ensured
      2. It is ensured that the value of the executeAt field is a datetime in the future
    • If the payload was valid
      1. The operation is added to the DynamoDB Table
        dynamodb.put_item(TableName='ScheduledOperations', Item={
            'scheduleID':{'S': str(uuid.uuid1())}, 
            'executeAt':{'S': event['executeAt']}, 
            'operationTopic': {'S': event['operationTopic']},
            'operation':{'S': event['operation']}
        )
        
      2. The Lambda Function PublishScheduledOperationsDBContents is invoked, which publishes the items of the Table to dt/neo/scheduled/res
        • todo: link function code Gist
      3. The Step Function MQTTWaitThenSendBack is invoked and passed the original payload
        1. This function waits until the specified time
        2. Then invokes the TestPublishToMQTT Lamda Function, passing it the same payload
          1. This function publishes the operation as a payload to the operationTopic payload
      4. A success/failure message is published to responseTopic
    • If the payload was invalid
      • A failure message is sent to the responseTopic field