The Internet Of Things with Scala – Part 2

by
Tags: , , , , , ,

This is a continuation of my Internet of Things with Scala posting. In this installment I will go over the assembly of the device that will be used to capture the soil moisture data and send it to an MQTT broker so that it may be picked up by the Scala/Akka based application.

The Parts

The main component of the soil sensor module will be the Particle Photon pictured below:


Image from SparkFun by Juan Pena licensed under the CC BY-NC-SA 3.0 license.

This board was chosen for several reasons. It is a fairly small device measuring about 2 inches by 1 inch so it will fit nicely into a small container. It comes with a Broadcom Wi-Fi chip built in for wireless communication and I was able to purchase it for $19 at SparkFun.
For the actual moisture sensor I decided to go with the SEN-13322 also purchased from SparkFun.


Image from SparkFun by Juan Pena licensed under the CC BY-NC-SA 3.0 license.

This is a fairly inexpensive component and does have some warnings about degradation under constantly wet conditions but we should be able to mitigate this by polling for the data infrequently as mentioned in the hookup guide. In addition to this, the component will be sealed with silicone conformal coating to further help prevent oxidation. If it doesn’t hold up well, I’ll look for a better sensor but I’ll start with this one for the time being. The other minor components include the 3-Pin Terminal, a prototype breadboard to mount it on and some wiring.

The Assembly

I began with building out the assembly for the soil sensor itself. First I soldered the 3-pin terminal onto the soil sensor so that I could easily connect and disconnect wires to it during the testing phase. I used stranded 22 AWG wire from a wire assortment package I bought. Stranded wire is better for this purpose as it flexes easier than standard solid core wire. To make it easier for the wires to mount in the 3-pin terminal, I soldered the ends prior to mounting them.

I mounted and soldered the 3-pin terminal onto the soil sensor using the provided 3 soldering points.

The underside of the sensor shows that the pins are soldered to the SIG, GND and VCC connectors. The VCC is the power input for the sensor, the GND is the ground connector and the SIG is the connector that the sensor level will be sent back onto and the connection on which the Photon will gather input from.

For the testing phase, I used a short set of wires to run from the Photon device to the sensor. In wrapped the wire with heat shrink readily available from Sparkfun. When I go to actually put it in the garden, however, I will likely have longer runs and will likely use some form of ribbon cable.
Pictured below is the end of the wrapped cable where the connection is made.

Since the sensor itself contains some small circuitry and will be placed under ground, I put a drop of the silicon conformal coating mentioned above onto those components to form a seal and protect it from direct contact with the soil.

I will eventually coat the terminal block and the wire connections but not until I’ve installed it in the garden and determined that the length of the wire is adequate.

The following is the wiring diagram for the photon and the moisture sensor:

The Particle Photon Code

// This #include statement was automatically added by the Particle IDE.
#include "MQTT/MQTT.h"
// Configure the incoming signal pin for the moisture sensor.
int sensorPin = A0;
// Configure the periodic power output pin
int powerOut = D0;
// Configure the Diagnostic LED
int diagnosticLed = D7;
// Unique identifier for the device
String deviceId="/garden/aisle/1/moisture/1";
// Configure the IP address of the MQTT Client
byte server[] = { 192,168,117,86 };
// Iniialize the MQTT Client for port 1833
MQTT client(server, 1883, NULL);
// This gets executed  before the loop defined below.
void setup() {
  //Set the pin mode to output
  pinMode(diagnosticLed, OUTPUT);
  // Configure the input pin for sensor input signals
  pinMode(sensorPin, INPUT);
  // Configure the output pin for sending power to the sensor.
  pinMode(powerOut, OUTPUT);
  // Configure the serial interface for debugging.
  Serial.begin(9600);
  Serial.println("Connecting to MQTT server ");
  // Connect the the spark MQTT service.
  client.connect("sparkclient");
}
// This is the loop that gets repeatedly called after the setup code has completed.
void loop() {
  blinkDiagnostic(1, 100);
  // Turn on the power to the sebnsor by seting the output pin to high.
  digitalWrite(powerOut, HIGH);
  // Read a value from the signal line
  int sensorValue = analogRead(sensorPin);
  // Send the moisture reading for this device to the particle cloud service
  bool result = Particle.publish("moisture", String(sensorValue));
  Serial.println("Publish of Sensor value " + String(sensorValue) + " to the Particle Cloud returned " + String(result));
  // Check if the MQTT client is connected
  if (! client.isConnected()) {
      // Display three diagnostic led pulses to notify that we are unable to connect to the MQTT server.
      blinkDiagnostic(3, 100);
      // Attempt or Re-attempt a connect the the spark MQTT service.
      client.connect("sparkclient");
  }
// Send the moisture reading for this device to the MQTT service
  bool mqttResult = client.publish(deviceId, String(sensorValue));
  Serial.println("Publish of Sensor value " + String(sensorValue) + " to the MQTT server returned " + String(mqttResult));
  // Turn the power on the sensor back off to prevent the sensor from degrading
  // and to conserve battery life.
  digitalWrite(powerOut, LOW);
  // Pause for 60 seconds until the next reading
  delay(60000);
}
//The function that handles the event from IFTTT
void blinkDiagnostic(int numberOfBlinks, int duration){
  int cnt = 1;
  while(cnt <= numberOfBlinks) {
    // We'll turn the LED on
    digitalWrite(diagnosticLed, HIGH);
    Serial.println("=== Turn On");
    delay(duration);
    // Then we'll turn it off...
    digitalWrite(diagnosticLed, LOW);
    Serial.println("=== Turn Off");
    delay(duration);
    cnt += 1;
    Serial.println("=== Count " + String(cnt));
  }
}

Configuring the Scala based Server

As you can see on line 14 of the code above, we’ve configured a unique identifier for the sensor as the value /garden/aisle/1/moisture/1. This identifier must be configured in the Scala based server so that a monitor will be initialized to receive values from that device. This is configured in the application.conf file located under the server/src/main/resources directory. We described this configuration in the first article when we set up a mock device to test that the server was behaving as expected. We now want to configure this additional device in that same configuration section so the configuration will now appear as follows:

device-configurations = [
  { id = "devices/mock/" },
  { id = "/garden/aisle/1/moisture/1" }
]

Loading the firmware onto the Photon



Before you can load firmware onto the photon, you must first go through a configuration process for the Photon Particle. Here are the directions for doing the initial setup. Once the setup is complete, you can use the online IDE to flash the code onto the particle. Before you flash the code onto the Particle board, you’ll need to change the value on line 17 of the code above so that it reflects the IP address of the machine where the MQTT server will be running on. Once this is done and you’ve flashed the code onto the particle, you should be able to start the application.

Running the Application

Follow the directions in the README.md to start up the Scala application server. Once you have the application running, you should be able to observe in the terminal where you started the application that once every sixty seconds you will see a debug line appear that should resemble the following:

 [DEBUG] [07/25/2016 12:33:28.544] [iot-series-akka.actor.default-dispatcher-3] [akka.tcp://iot-series@127.0.0.1:2552/user/device-monitor..garden.aisle.1.moisture.1] Dispatching device event DeviceDataReceived(/garden/aisle/1/moisture/1,37,2016-07-25T16:33:28.480Z) for device /garden/aisle/1/moisture/1

What’s Next?

In the next article I’ll be adding an ambient light sensor. Generally when watering a garden, you’d like to do it when the sun is not shining directly onto the plants as the water will act as a magnifying glass and will burn the leaves on the plants. In addition to this, if you water during non-peak sunlight hours, the ground will stay moist for a longer period of time. At first it may seem that this could be accomplished through the use of weather and time however that will not cover situations such as when the sun is still in the sky but is shadowed by a home or even a fence. For this reason I think the light sensor will be more effective. I’ll have to consider scenarios where clouds shadow the sun so perhaps I’ll have to validate how long the shadow condition has existed prior to turning on the water. I’ll investigate this in my next article.

All sources for this project can be found here.