Dear candidate.
Imagine this scenario. An IoT device that measures various weather data is sending payloads to our servers.
Our goal is to parse the payload that is packed in a binary format and store it in our database. While we are analysing
the data we can also react on the various parameters.
Your task is to create an alert system that sends an email to a customer if a value exceeds a user defined threshold. Examples could be:
- battery level drops below below 2300 mV
- relative humidity level exceeds 90%
- air temperature drops below 13 degrees C
- others
Enclosed in this folder you will find 3 files.
- payloads holds examples of binary packed data from the station
- DataParser.php is a helper class with static methods to decode the station data into a more readable format
- example.php is an example of how to use the DataParser method
!!! Two important requests
- the service for dispatching emails should be asynchronous, separated from the service that is ingesting device data.
In production environments we need to be able to respond to the IoT device as soon as possible and cannot wait for
emails to (potentially many) clients to be dispatched
- make sure the client does not get too many alerts. If the device sends data every 15 minutes, he should not be alerted every time, even if the condition is met.
For achieving your task you can use any additional service that you might need. You can use any method to deliver payloads to your script - POST data, API request, CLI
In case of any questions, don't hesitate to ask.
- I used the Lumen framework because I believe he is fast enough to do the job.
- For the proporse of this app, I used Redis to control and send e-mail asynchronous
- Also is super fast.
-
Payloads
- Database, or service that provides payloads from the weather station
- I mocked up a solution for simulates this service
-
User manually call payloads
- I created an endpoint where it is possible to call one payload at once
- Endpoint:
pessl.localhost:8001/api/payload
2.1. Command to call payloads
```shell
php artisan cron:checkPayloadCommand
```
2.2. Api Save Parameters
- To access the frontend http://pessl.localhost:8001/front
When you change the e-mail, I get info from Cache to fill all parameters automatically
-
API Process Payload
- Api to get payloads
pessl.localhost:8001/api/payload
- Api to get and post user data
pessl.localhost:8001/api/user
- Place where I did the logic to process the payload and check parameters
- Create an alert or not
- Dispatch to queue
- Api to get payloads
-
Redis
- I used Redis keys to control alert frequencies
- I used Redis Queue for e-mails and payloads
- I used Redis to save parameters
-
Process payload queue
- Run the service who check if it's necessary send an alert based on a payload
php artisan queue:listen --queue=receive-payload
5.1. Process e-mail queue
- Process the queue to send alerts.
```shell
php artisan queue:listen --queue=send-email-alert
```
-
Email Sent
- You configure the e-mail frequency in the frontend page
http://pessl.localhost:8001/front
- You configure the e-mail frequency in the frontend page
-
Install dependencies.
I use docker/docker-compose to runs all environment
# check docker / docker-compose version docker --version && docker-compose --version
This environment contains:
- nginx
- php7.3
- redis
- phpredisadmin
-
Start the project
#probably will take an while util install all dependencies docker-compose build #up the containers docker-compose up -d #create vendor folder composer update #run the lumen service php -S localhost:8001 -t public #checkup the containers IPS sudo docker inspect -f '{{.Name}} - {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $(sudo docker ps -aq) #to run the payload service php artisan cron:checkPayloadCommand #to consumes the queue php artisan queue:listen #to see logs from sended e-mails php artisan cron:logs
-
Environment Variables
See the complete .env file
#redis connection QUEUE_CONNECTION=redis REDIS_CLIENT=predis REDIS_HOST=localhost REDIS_PASSWORD=null REDIS_PORT=6379 #name of queue to send email REDIS_QUEUE_NAME=send-email-alert #name of queue to process payload REDIS_PAYLOAD_QUEUE=receive-payload #api key from sendgrid to delivery fast emails
<<<<<<< HEAD SEND_GRID_API_KEY=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
SEND_GRID_API_KEY={SENDGRIDKEY}
0ca66128f8ee4b66c8ad46e2c99491be54db1080
#default parameters from user
PARAMETER_BATERY_MIN=2300
PARAMETER_RELATIVE_HUMIDITY_MAX=90
PARAMETER_AIR_TEMPERATURE_MIN=13
PARAMETER_DEW_POINT_MIN=90
#send payload frequency by seconds
SEND_PAYLOAD_FREQUENCY=15
#default value for send e-mail frequency in hours
SEND_EMAIL_FREQUENCY=8
#main e-mail
[email protected]
# to test if a payload is match with de max or min parameters
PAYLOAD_TO_TEST=93F9gAFwAG8AAJ0DQANaCQAAmAe\/BL0ExAToA+gD6APo\/+j\/6P++BLwEAAAAAA8=
4. **Unit Tests**
```shell
#to run unit tests
vendor/bin/phpunit
#check if payload parameters its respect the user parameters
#change the PAYLOAD_TO_TEST env variable
vendor/bin/phpunit --filter parameters_check_up
-
Lint code
#to lint the code vendor/bin/phplint
-
How to use
-
Avaliable endpoints to acess
# Acess the frontend to input some parameters pessl.localhost:8001/front # Endpoint payload pessl.localhost:8001/api/payload # Endpoint user data pessl.localhost:8001/api/user?email=${EMAIL} # To acess php Redis Admin pessl.localhost:8003
- Don't forget to run
composer update
- Check if the port 8001 its already use by another container or process
lsof -i -n -P | grep 8001