Akka Remote Messaging With Raspberry Pi

December 08, 2017

In this tutorial, we will create an Akka Remote system and send a message between localhost (Ubuntu/Raspberry Pi) and the remote host (Raspberry Pi).

Git Hub Project

The complete project can be cloned from here.

Prerequisites

Please make sure both Scala and SBT are installed on your local Linux system and Raspberry Pi. Please follow my tutorial post here to install.

Reference

  1. Akka docs
  2. Remote Example

Add Dependencies

We will be using scala version 2.12.4 and akka-remote library. Add the following line to the build.sbt. You can check the latest version from here.

scalaVersion := "2.12.4"
libraryDependencies += "com.typesafe.akka" %% "akka-remote" % "2.5.8"

For SBT, we will be using 0.13.16. Therefore, add the following line to build.properties

sbt.version=0.13.16

Note: These dependencies are for both local and remote host.

Overall Project layout

This is the overall layout for our project (both local and remote host). If you are starting from the scratch, you will need to follow this layout. Otherwise, you could just clone the entire project and make a modification to it.

Loal Actor IntelliJ Dir

Overall Setup

Before we begin, I’ll just brief what we are going to do. First, we will create a configuration file for both local (Ubuntu) and remote (Raspberry Pi). The local system uses 127.0.0.1 and the remote system uses 192.168.1.101. Both local and remote systems are on the same network connected via a router. The local machine sends a message every 1 second and the remote machine replies back when it receives from the local machine.

graph LR; A(local host - 127.0.0.1)-->B(remote host - 192.168.1.101)

Configuration File

To enable remote messaging in our project, we should create and add an application.conf file under <project folder>/src/main/resources folder. You can look up our project layout again that I mentioned above.

Local Actor Configuration File

Remember that local machine will use 127.0.0.1. We don’t really particular about port number here. Therefore, we just use 0 and the system will use any available port.

1
2
3
4
5
6
7
8
9
10
11
12
akka {
  actor {
    provider = remote
  }
  local {
    enabled-transports = ["akka.remote.netty.tcp"]
    netty.tcp {
      hostname = "127.0.0.1"
      port = 0
    }
  }
}

Local actor

At line 7, we use context.actorSelection to look for the remote machine IP address and Actor name. At line 11, we are using scheduler to send a message every one second to the remote machine.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import akka.actor.{Actor, ActorSelection, Cancellable}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._

class LocalActor extends Actor {

  val remote: ActorSelection = context.actorSelection("akka.tcp://RemoteActorSystem@192.168.1.101:1212/user/RemoteActor")

  val TalkToRemote = "talkToRemote"

  val scheduleCancellable: Cancellable = context.system.scheduler.schedule(0.seconds, 1.second, self, TalkToRemote)

  def receive = {
    case TalkToRemote =>
      remote ! "Hello from the Local Actor"

    case msg: String =>
      println(s"LocalActor received message: '$msg'")
  }
}

Local actor App

This is the main entry point to run our Local Actor application. At line 5, we just use LocatActor class to instantiate as an actor.

1
2
3
4
5
6
import akka.actor.{ActorSystem, Props}

object LocalActorApp extends App {
  implicit val system = ActorSystem("LocalSystem")
  val localActor = system.actorOf(Props[LocalActor], name = "LocalActor")
}

Remote Actor Configuration File

Please remember that we set up our remote host (Raspberry Pi) IP address as 192.168.1.101. You should change to the different IP address in this configuration file according to your Raspberry Pi IP address. The port number should be same for the port number that we defined in ActorSelection at Local Actor.

1
2
3
4
5
6
7
8
9
10
11
12
akka {
  actor {
    provider = remote
  }
  remote {
    enabled-transports = ["akka.remote.netty.tcp"]
    netty.tcp {
      hostname = "192.168.1.101"
      port = 1212
    }
  }
}

Remote actor

This remote actor is just sending back a message when it receives from Local Actor.

1
2
3
4
5
6
7
8
9
import akka.actor.Actor

class RemoteActor extends Actor {
  def receive = {
    case msg: String =>
      println(s"Remote Actor received message '$msg'")
      sender ! "Hello from the Remote Actor"
  }
}

Remote Actor App

This is also the main entry point to run our Remote Actor application.

1
2
3
4
5
6
import akka.actor._

object RemoteActorApp extends App  {
  val system = ActorSystem("RemoteActorSystem")
  val remoteActor = system.actorOf(Props[RemoteActor], name = "RemoteActor")
}

Run Remote Actor

At a terminal, go to the folder (Remote Actor in this case) at Raspberry Pi. Type in sbt and then follow by run command. Now the remote actor is waiting for messages from the local actor.

Run Local Actor

Similarly, go to the folder (Local Actor in this case) at Ubuntu/Linux system. Type in sbt and then follow by run command. Now local actor started sending at the 1-second interval.

Result

At local host terminal, you should see this message at every 1 second.

LocalActor received message: 'Hello from the Remote Actor'

At remote host (Raspberry Pi) terminal, you should see this message at every 1 second.

Remote Actor received message 'Hello from the Local Actor'

Note: If you could not manage to receive any message, you should check IP address of the remote host, configuration file and actor selection.