This is the first blog post that I am writing to share my experience with the Phoenix framework in building an Iot application. I have written a blog post about Elixir and Phoenix here. The objectives that we are going to achieve in here are
A ‘Model View Controller’ scheme for the users. So that the users can register themselves in the application and have a login access to monitor as well as control their machines.
A messaging interface between the machine and the user so that the application can be pretty much asynchronous and fast. This will accomplish the goal of an user specific Iot architecture, where a user can control and monitor only his/her machines, not others. There is no need of refreshing the pages to know the current state of the machines as we will be using websocket connections to make it a real time application, where the connection to the server never goes away.
Writing machine clients. The clients which will help the machine send sensor outputs to the server.
Phoenix is a framework written in Elixir programming language which runs on Erlang VM. The installation instructions for the framework is given here. After successful installation, let’s start building the application.
To create our Iot project run the following in the terminal.
$mix phoenix.new iot
Now, enter into the application. Note: you must have postgres installed in your system for the database requirements.
Now run the server or you can run the server within an interpreter too.
$mix phoenix.server or $iex -S mix phoenix.server
Now we can view the application at http://localhost:4000/. Now let’s change the contents of some files to have the default page as the login page for users. To achieve that, we should have an users table in the database with the details of the users as attributes. For that, we have to generate a users model using the mix model generator.
$mix phoenix.gen.model User user username:string encrypted_password:string email:string token:string
It will create a file called
user.ex in the
web/models/ directory. Now the users table has 4 attributes called the
token. But, to register a user with a password for login purposes, we should have two virtual fields, the
password field and a
password_confirmation field. These are virtual attributes and they are never stored as attributes of the users table. The password after entered in the registration form is converted into a encrypted form and saved in the database as encrypted password. When the user logs in later, again that entered password is encrypted and matched with the encrypted password already saved in the database for that user. This process helps in a secured access by not storing the password anywhere during the login or register process. The user only knows his password, no one else knows, not even the admins of the application. :D
Now, let’s add those virtual fields and have some validations for the attributes in
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
Here, the required fields doesn’t include the
encrypted_passwordfield and the reason is obvious. The
encrypted_password we are going to generate later. Now, to register the users, we should have a registration controller, a registration template of course with a form to be filled by the users, and a url like http://localhost:4000/registraion. So, let’s modify the
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
Now we have added 2 routes, one to get the content (The user registration form) and the other is a post request for the same. Now we need to have a
registration_controller.ex file in the
web/controller directory, where we are going to write the
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Here in the new method, we are accepting the attributes of the user in the variable
changeset. The create method checks if those required fields fulfill the validations present in
changeset.valid? method and stores the user in the database and renders the page_index page. (The default page at http://localhost:4000/ ). If the
changeset.valid? is not fulfilled again the new registration page will open up.
The saving of the user in the database by creating the
encrypted_password is done here by the
Password library. Let’s write the password library with the
generate_password_and_store_user that we have just used in the registration controller and other methods.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
Here I have used
comeonin package to encrypt the password. You can get it by adding it to the dependencies in the mix.exs file as
1 2 3 4 5 6 7 8 9 10
Then install it through
generate_password_and_token method generates the encrypted password and a token(to be used later) for the user. The
generate_password_and_store_user method stores the user in the database. Now, it’s time to add a template for the new registration page. Create a directory named registration in the templates folder and add a new.html.eex file in it. Fill it with the content below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
The session_login button is now commented because we haven’t added the sessions controller yet.
Let’s try it all out. First we have to create the database for the application using ecto.
Then, we have to migrate the changes that we have in the users model.
Now we have to restart the server as we have added a new lib file called
password.ex. Then, check if that registration form at http://localhost:4000/registration/ is working. If it renders the default phoenix page with a “You are Sucessfully Registered :P”, it’s working.
Now let’s replace the default phoenix page with a login page for the users. Let’s understand what a session is. Sessions are the users’ active time spans after login. A sessions controller matches the username and password of the user and renders the pages. A session controller stores the users data (you can customize the data to be stored) for the session. It is recommended to store minimum required data like only the username or the email in the session. With a logout request, we free the session variables. So, now we have to add a
login and a
logout route in the
router.ex along with a
new route for the session. The page route will be replaced by the
new method of the session.
1 2 3 4 5 6 7 8
Clearly from the routes, we now know that we have to write a
session_controller.ex in the
web/controllers directory with new, create and delete methods in it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
The code above is self explanatory. The
sign_in method lets the user log into the pages. The
put_session method stores temporary session data. In this case the user is saved in the session as
:current_user. Now, we will write the new template for the login form. Create a folder called session in the
web/templates/ folder and a file called new.html.eex in it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
Now, we can uncomment the line in
web/templates/registration/new.html.eex for the session login path. And we change the
create method of the registration controller to render the login page rather than the default phoenix page.
1 2 3 4 5 6 7 8 9 10 11
Now, where will it go after login? We must have some place where it should move to after login and we must have a control over that page so that that page can not be opened unless the user is logged in. That is why the line
redirect(to: energy_meter_path(conn, :index)) is added in the
sign_in method (EnergyMeter is our Iot device). We will create a energy_meter template with only the username of the user in it. At first, let’s edit the router.ex file.
1 2 3 4 5 6 7 8 9
Now let’s create a
1 2 3 4 5 6 7 8 9 10
Now let’s write the template for this.
1 2 3
This has the username of that user and a logout button. The controller has a Authenticate Plug, which ensures the authenticity of the current user. If the user is not logged in, this Plug helps not to show any page in the EnergyMeter controller. Let’s write that Plug. We have to create a directory called
authentication in the
web directory and add
authenticate.ex file in it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
The code is self explanatory. If a user is trying to get the energy_meter index page without logging in, it will throw the error as “You Need to be signed in to view this page !”. Now try that all out by going to http://localhost:4000/.
Note: a view must be added with all the controllers. Otherwise, it will throw an error. A demo view in the views folder is given below.
1 2 3 4
Now, the authentication part is done. In the next part, we will code the messaging application that is needed for users to listen and control their machines.
Happy Hacking !