Introduction: Flood Detection in a Smart Streep Lamp Post

These materials and the information contained in this instructable are provided by students enrolled at Software of Places (www.softwareofplaces.com) Class at PUC-Rio University. The content represented here is the student’s final project for class evaluation porpoise published by the student and is solely the responsibility of the page author. Statements made and opinions expressed are strictly those of the author and not of PUC-Rio University.

The objective of this project is prototype an intelligent lamp post focused on water flood detection. This project is also part of Software of Places course from Department of Informatics at PUC-RIO.

Main features

  • Detect imminent water floods;
  • Turn a lamp automatically on/off;
  • Dynamic traffic display;

Hardware required

  • Intel Galileo Gen 2
  • Grove LCD RGB (Traffic sign)
  • Grove LED (Traffic sign)
  • Grove Moisture Sensor (Flood detection)
  • Drain (Flood detection)
  • Grove Temperature Sensor
  • Grove Light Sensor (Lamp control)
  • Grove Relay (Lamp control)
  • 1 12V DC lamp (Lamp control)

Running the system

  1. Download the code (main.js and package.json)
  2. Connect all the sensors according to the images and as decribed on code
  3. Open it on Intel XDK IoT Edition
  4. Upload and run

On the next steps, we're going to show how to build the system and also explain some decisions made.

At the end, some evolutions and improvements are discussed.

Step 1: Initial Setup and Temperature Sensor

Adding Cylon.js

This project used the Cylon.js framework (http://cylonjs.com/)

Cylon.js is a JavaScript framework for robotics, physical computing, and the Internet of Things. It makes it incredibly easy to command robots and devices

The greatest advantage of Cylon.js is that the same code should run on different devices (Intel Galileo, Arduino, Raspberry Pi, etc).

To use it, add the following dependencies on package.json

"cylon": "1.2.0",
"cylon-intel-iot": "0.8.0",
"cylon-gpio": "0.27.0",
"cylon-i2c": "0.23.0"<br>

And on main.js

var cylon = require("cylon");
cylon.robot({
	name: "floodDetection",

	connections: {

		galileo: { adaptor: "intel-iot" }
        },
        devices: {	
	},
	work: function() {
	}
});<br>

Plugging the temperature sensor

Before we start the development of the flood detection feature, let's start with the temperature sensor.

Plug it at port A2 and then run the following code:

var cylon = require("cylon");
cylon.robot({
	name: "floodDetection",
	connections: {
		galileo: { adaptor: "intel-iot" }
	},
	devices: {
		temp: { driver: "upm-grovetemp", pin: 2, connection: "galileo" },
	},
	debugValue: function(message, value, status) {
		console.log(new Date(), message + " = " + value + " [" + status + "]");
	},
	processBuffer: function(/*Value reported by the sensor*/ currentValue, /*Array*/ buffer, /*Context*/ that) {			
		// Initialize buffer if null		
		if (!buffer.values) {
			buffer.values = [];
		};
		
		// Add currentValue to buffer		
		buffer.values.push(currentValue);
		
		// Check size of buffer. If it has reached
		// its buffer.MAX_SIZE, then take some action
		if (buffer.values.length == buffer.MAX_SIZE) {			
			
			// Get average value. This value is gonna be used
			// to trigger an action.
			var sumOfAllValues = 0;
			buffer.values.forEach(function(oldValue) {
				sumOfAllValues += oldValue;
			});
			var avgOfAllValues = (sumOfAllValues / buffer.MAX_SIZE);
			
			// The action itself
			buffer.action(that, avgOfAllValues);
			
			//Reset buffer
			buffer.values = null;
		};
		
		return buffer;
	},
	work: function() {
		var that = this;
		var temperatureBuffer = {
			MAX_SIZE:	5,
			data: 		null,			
			action: 	function(that, avgValue) {
				that.debugValue("temperature", avgValue);
			},
		};
	    setInterval(function() {
			that.temperateBuffer = that.processBuffer(that.temp.value(), temperatureBuffer, that);
    	}, 1000);
	}
});<br>

The output should show the temperature (in Celsius) each 5 seconds.

Buffered values

The temperature value reported by the sensor is captured each second and put in a buffer dedicated to the values of this sensor. This buffer is controlled by the method processBuffer, which takes as parameters (1) the current value of a given sensor, (2) the buffer object of this sensor and (3) the variable 'that'.

The buffer object (see temperatureBuffer) should have at least:

  • MAX_SIZE - the maximum size of the buffer;
  • data - an array containing values reported by the sensor;
  • action - Javascript function triggered by processBuffer;

The method bufferedReader will stack the last MAX_SIZE values reported by a given sensor. When 'data' array size is equal to MAX_SIZE, this method will calculate the average value from the values contained in this array. Then, the function passed as parameter 'action' is going to be executed using this average value and the variable 'data' will be set to null.

The objective of this buffer is prevent discrepant values.

On the above code, the 'action' function will simply output the average temperature. At the following steps, this function will be more useful.

Step 2: Flood Detection and Road Display Board

The main feature of this project is the flood detection. To detect it, we will use the Grove moisture sensor installed inside a drain. This sensor is suitable for this because (according to https://software.intel.com/en-us/iot/hardware/sen...

This sensor can be used to detect the moisture content of soil or whether there is water around the sensor. As the moisture content increases, so does the value that is read {quote}

After a certain value, we could say that a flood is imminent. To get this value, we will use the same processBuffer explained in the last step and an associated moistureBuffer.

OBS: From now on, only the relevant snippets of the code will be shown. In case of doubt, remember that the full code is available at the beginning.

devices: {
	// ...
	moisture:	{ driver: 'analog-sensor', pin: 0 },
	led:		{ driver: "led", pin: 8, connection: "galileo" },
	screen:		{ driver: "upm-jhd1313m1", connection: "galileo" }
},
writeMessage: function(message) {
    var that = this;
    var str = message.toString();
    while (str.length < 16) {
      str = str + " ";
    }
    that.screen.setCursor(0,0);
    that.screen.write(str);
    that.screen.setColor(255, 242, 0); //Yellow~Green    
},
var moistureBuffer = {
	MAX_SIZE: 		30,
	data: 			null,
	status: 		'INITIALIZING',
	blinking:		null,
	action:			function(that, avgValue) {
		var THRESHOLD = 670;
			
		if ((avgValue > THRESHOLD) && (this.status != "FLOOD")) {            
			// Condition to trigger flood alert
			this.status = "FLOOD";
			that.led.turnOn();
			that.writeMessage("FLOOD RISK");
			this.blinking = setInterval(function() {
					that.led.toggle();
			}, 200);
		} else if ((avgValue <= THRESHOLD) && (this.status != "OK")) {            			// Condition to remove flood alert
			this.status = "OK";
			that.led.turnOff();
			that.writeMessage("Road open");
			clearInterval(this.blinking);
		};
		
		//that.debugValue("moisture", avgValue, this.status); //uncomment for debug purpouses
	}
},
setInterval(function() {
	//...
	that.moistureBuffer = that.processBuffer(that.moisture.analogRead(), moistureBuffer, that);		
	}, 1000);
};

The THRESHOLD is the value reported by the moisture sensor when the drains is almost completely filled with water. We will consider this as imminent state of flooding (the volume of water coming to the drain is equal or greater than its output flow rate). Remember that this THRESHOLD value will be compared to the average of last MAX_SIZE values obtained from the moisture sensor because of the processBuffer method.

When a imminent flood is detected, the drivers on a road should be warned before they reach this stretch. For this, the Grove LCD display and the Grove LED will be used to simulate a road display. In this situation, the LCD display will show the message "FLOOD RISK" and the LED will start to blink. On normal situation, the LCD will show "Road open" and the LED will be turned off.

Step 3: Auto On/off Post Lamp

The last feature is to automatically turn on (and off) the lamp of the post.

To implement this function we need the Grove relay, Grove luminosity sensor and a lamp connected to a power source (in this project it was used a 12V LED Lamp).

The wiring is shown at above images. Here's the following code to control the lamp:

devices: {
	light: { driver: "analogSensor", pin: 3, connection: "galileo" },
	relay: { driver: 'relay', pin: 6, connection: "galileo", type: "closed" },	
},
var luminosityBuffer = {
	MAX_SIZE: 	30, //seconds
	data: 		null,
	status: 	"LAMP ON",
	action: 	function(that, avgValue) {
		var THRESHOLD = 150;		
		if (avgValue < THRESHOLD) {
			that.relay.turnOff();
			this.status = "LAMP ON";
		} else {
			that.relay.turnOn();
			this.status = "LAMP OFF";
		};		
		that.debugValue("luminosity", avgValue, this.status);
	},
};
setInterval(function() {
	//...		
	that.luminosityBuffer = that.processBuffer(that.light.analogRead(), luminosityBuffer, that);
}, 1000);<br>

IMPORTANT: Certify that the luminosity sensor is out of the reach of the lamp focus. If you don't pay attention to this, the lamp will be alternating on and off in a situation where the lamp should be always on. This occurs because the luminosity sensor will be reporting high values while the lamp is on.

Step 4: Future Improvements

Due to limitations of time, it wasn't possible to develop some other features. Here are some suggested improvements.

API for remote operation

It would be helpful to interact with the sensor remotely to read the values reported by the sensors and also change the message displayed on the LCD display and/or turn on/off the lamp. When implementing this, pay attention to operation mode of the lamp post. For example, when a user changes the value of the LCD display while in a normal state (no risk of flood), what would be the most important message in case of flooding? The user message or the system message for flood risk?

Improve rain detection

Besides detecting rain with the moisture sensor at the drain, it would be helpful to detect raining using a rain sensor at the top of the lamp post for example. One of the limitations observed is that a light rain is not detected this way. If we could detect this situation, the traffic display could show a message like "Road slippery". Also, we could predict the iminente flood more precisely based on the rain volume.

Detect clogged drain

Suppose the second topic discussed here has been implemented (Improve rain detection). Based on the values reported by both the rain sensor and moisture sensor at the same time, it would be possible to detect a clogged drain if the values reported by the rain sensor (at the top of the lamp post) are much greater than the values reported by the moisture sensor (at the drain).

Auto-dim lamp and movement detection

Another interesting improvement to save energy is reduce luminosity of a lamp - or even turn it off - based on movement and time. For example, between midnight and 4 a.m., the luminosity of the lamp could be reduced. Also, if a sensor detects someone near the post or a vehicle/bicycle moving, the lamp could brighten up for a while.