Jan 17, 2019

To demonstrate how Slang interacts with IoT (Internet of Things) devices we will build a small demonstration plant control system which monitors temperature, humidity and soil moisture. You will also see how rules can be defined and sensor data processing can be achieved with Slang. In a future post we will look at how to get notified by email when you should worry about your plant.

What we need

To gather information and send it to our Slang operator, we need a device capable of transmitting data to our Slang operator via WiFi. We recommend NodeMCU for that. It is only a few euros and has everything you need to get you started, especially WiFi capabilities. Also most Arduino sensors work with it because NodeMCU is Arduino compatible.

We need a moisture sensor and a humidity and temperature sensor. These are typical sensors to start experimenting with IoT. To have some direct feedback from our devices we use two RGB LEDs.

All of these items are pretty standard. We bought ours from AZ-Delivery but you can get them from many other places as well of course.

IoT accessories we will be using

Our lab rat, err plant

So what do we want to do exactly? The goal is to monitor temperature, humidity and soil moisture of our plant. We want to log these values and run some analysis on them later.

Our lucky plant is a coffee plant that decorates our office since we moved in here in July last year. We do not have a 'green thumb' to put it mildly. So hopefully it won't have to suffer in the future. And maybe we can even drink self-cultivated coffee someday?

A coffee plant decorating our Bitspark office

The DHT11 sensor

The DHT11 sensor is a very cheap and unfortunately not very precise sensor. For our purpose however it is completely sufficient.

We connect the signal pin with D3 of our NodeMCU and the RGB pins of the LED with D5, D6 and D7, respectively. Of course, you also need to connect GND and Vin (see picture below).

Of course we need to program the NodeMCU so that they know what to do. We want them to connect to our office WiFi and an MQTT broker running on a computer. We will replace it with a Raspberry Pi in a future blog post, but for now it is sufficient to show the basic idea.

We have created a GitHub repository containing the code for both sensors. You find the repository for the DHT11 sensor here: Bitspark/example-iot-dht11 We will only explain the crucial parts of it here.

if (millis() - lastMeasure > 10000) {
lastMeasure = millis();

ledOn(LED_BLUE);
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
ledOff(LED_BLUE);

if (isnan(humidity) && isnan(temperature)) {
ledOn(LED_RED);
} else {
ledOn(LED_GREEN);
char str[16];
sprintf(str, "%.0f %.0f", temperature, humidity);
mqttPublish("/bitspark/office/plant/coffee1/dht", str);
}

lastLight = millis();
}

This is a part of the loop function which is being executed over and over again until the device is shutdown or put into sleep. As you can see, we measure every 10 seconds with dht.readTemperature and dht.readHumidity and indicate a measurement with the blue LED. The LED functions ledOn, ledOn and ledOff are custom functions implemented in a different file. You also find it in the GitHub repository.

After the measurement, we need to check if it was successful. The DHT sensor uses a serial transmission which can fail sometimes - especially with our cheap DHT11 sensor. We do that with isnan. If it was successful, we switch on the green LED, otherwise we switch on the red LED.

The moisture sensor

The moisture sensor can be run in digital and analog mode. When running in digital mode, you can use the potentiometer to specify a threshold when it should output 1. We will be using the sensor in analog mode, which allows the NodeMCU to read a value between 0 and 1024. It uses an analog-digital converter that is connected with the A0 pin (analog pin).

We connect the analog signal pin with A0 of our NodeMCU and the LEDs like we did with the DHT11 sensor (see picture below).

The code for our moisture sensor is very similar. The only difference is that we use analogRead to read a value between 0 and 1024 from our analog pin. You find the code on GitHub as well: Bitspark/example-iot-moisture

Slang and MQTT

Now that we can measure the values we only need some logic which makes our system behave the way we want. And that's when Slang comes into play! Just to remind you, we want to log these values and keep them for later analysis.

First, you will need an MQTT broker. Its task is to keep track of all MQTT devices that have subscribed to it. Subscribe means that a device has signalled the broker that it is interested in messages of a certain topic. A topic is hierarchical and looks a bit like an HTTP path. /bitspark/room1 could be a topic all devices in room 1 of the Bitspark office push their messages to. /bitspark/room1/window/temperature could be the topic a thermostat at the window pushes its messages to. You can even use special character such as # or * as wildcards. Here is a good explanation on topics if you want to dive a bit deeper.

For this example, we use Mosquitto. It has everything you need and runs on most machines.

Slang has MQTT support already built in. There is an MQTTSubscribe and MQTTPublish operator which will subscribe or publish to a topic at your MQTT broker. From the broker's perspective there is no difference between a Slang MQTT operator and a true physical device connected to it.

Gather sensor data with Slang

We need to collect all data until we have enough to run some analyses on them. For that, we can use the Insert (file) operator. It takes arbitrary values and stores them in a file.

Before we have a look at what's going on there, let us go through some questions first.

What are operators exactly?

In Slang, operators are small worker units that perform a certain task. They take data (usually arriving at the top) and emit data (usually at the bottom). And they all run in parallel!

How many operators are there?

The answer to that question changes every day. There is a growing number of operators. We write many of them, but every Slang user can create their own.

How are Slang operators created?

There's two possibilities. Most of them are built with... operators. Existing operators can be combined by connecting them to form a new operator. You can built almost anything just by combining and nesting existing operators. But of course there has to be something like 'atomic' operators. These are called elementary operators in Slang and perform very rudimentary tasks. The Split operator for example takes a string and splits it into multiple strings at a separator you can specify (see last screenshot above).

How do connections work?

Connections in Slang are channels with a capacity. That means, if the operator the data is dedicated for has not finished its previous task yet, the value will still be put into the channel. That enables us to keep running everything at maximum speed without having operators wait for other operators to finish.

Now back to our example plant control operator. So what is happening there? First, let's follow the left flow. A gray 'trigger' is connected with MQTTSubscribe. This causes the operator to start upon starting the surrounding plant control operator. It will emit one item each time it receives a message from the MQTT broker specified via the form you can see in the second screenshot.

It subscribes at the topic where our DHT sensor pushed temperature and humidity to. Unfortunately what arrives is a string of the form "<temperature> <humidity>". So we somehow need to extract temperature and humidity therefrom.

This can be done with the above-mentioned Split operator. We need to specify the separator as " " (a space). It will emit two values per string it receives provided it is of said form.

But we do not want to store these two values as separate values in our database. We don't want to lose the information that they were measured at the same time. So what we do is take a Parallelize operator which collects two values and emits one combined item.

Just like that: [[a1, b1], [a2, b2], [c1, c2], ... [a(1|2) b(1|2) c(1|2), ...]

And finally these values can be stored with the file-based database operator Insert.

The right flow is much simpler because the data is already in the right form. We just need to convert the string into a number.

These conversions might seem a bit confusing right now. They don't really add much to the logic of an operator you build. But they are necessary to ensure the usage of correct types. We don't want to go too deep here and keep that topic for a following post. We are also working on a solution that deals with conversions automatically to further reduce complexity without losing the advantages of a typed system.

Hint subscribe our newsletter for updates

Setting up the sensors

Our Slang operator is now ready and waiting for data it can gobble up. So we will set up the sensors now.

We stick the moisture sensor in the soil close to the rim since we don't want to hurt any roots. The DHT sensor will be fastened to the pot as well so that it doesn't move and provides comparable measurements. Finally, we connect the batteries.

The result

After some time, we find several entries in our database files. We can use a plugin providing graphs directly from Slang Studio. To see if our moisture sensor works, we have watered the coffee plant at about the middle of our measurement series.

Graph of moisture resistance measurements (high means dry and low means moist)

As you can see, the moisture was indeed correctly detected as higher after watering the plant (lower means more moisture).

So much for part 1, we hope you enjoyed it. If you have questions don't hesitate to contact us via the contact form. In the next part we will do some more with Slang operators and add alarm features to our plant control operator. Maybe our coffee plant has even grown a bit bigger until then :)

What the hell is flow-based programming?

Explore an underestimated paradigm and see how it differs from what most people are using today.

Benchmarking Slang, Apache Storm and Apache Spark

See how stream processing with Slang performs compared to Apache Storm and Apache Spark.