Md. Khairul Alam
Published © GPL3+

Smart Parking System

ARTIK cloud-based smart parking system.

AdvancedWork in progress10 hours100,806
Smart Parking System

Things used in this project

Story

Read more

Schematics

Android App Screenshot

Android App using Artik Cloud Android SDK

Screenshot of Web Application

Block Diagram of Smart Parking Syatem

Parking lot using ultrasonic sensor

Parking lot using Photosensor

Code

Raspberry Pi (rainbow-parking)

JavaScript
Source code for raspberry pi
//rainbow parking data transfer
var webSocketUrl = "wss://api.artik.cloud/v1.1/websocket?ack=true";
var device_id = "Your Device ID Here"; // Rainbow parking DEVICE ID
var device_token = "Your Device Token Here"; //Rainbow parking DEVICE TOKEN
// require websocket module to connect 
// execute following two commands to your pi's terminal
// sudo apt-get update
// npm install websocket
var WebSocket = require('ws');
var isWebSocketReady = false;
var data="";
var ws = null;
// require serialport module to raspberry pi 
// execute following command to terminal
// npm install serialport
var serialport = require("serialport");
var SerialPort = serialport.SerialPort;
var sp = new SerialPort("/dev/ttyACM0", { //for serial communication with arduino 
    baudrate: 9600,  
// we are using UNO so baudrate is 9600, you might need to change according to your model
    parser: serialport.parsers.readline("\n")
});

var parking_state=0;// variable to check for parking state_gate

/**
 * Gets the current time in millis
 */
function getTimeMillis(){
    return parseInt(Date.now().toString());
}

/**
 * Create a /websocket connection and setup GPIO pin
 */
function start() {
    //Create the WebSocket connection
    isWebSocketReady = false;
    ws = new WebSocket(webSocketUrl);
	// this function invoked on successful connection
    ws.on('open', function() {
        console.log("WebSocket connection is open ....");
		// you must register for successful data transmission
		// registration is for authentication or secure data transfer
        register();
    });
    ws.on('message', function(data) {
      //this loop is called whenever the client sends some message
         handleRcvMsg(data); //data is send to the function handleRcvMsg()
    });
    ws.on('close', function() {
        console.log("WebSocket connection is closed ....");

    });      
    
}

/**
 * Sends a register message to /websocket endpoint
 */
//Client will only work when device gets registered from here
function register(){
    console.log("Registering device on the WebSocket connection");
    try{
        var registerMessage = '{"type":"register", "sdid":"'+device_id+'", "Authorization":"bearer '+device_token+'", "cid":"'+getTimeMillis()+'"}';
        console.log('Sending register message ' + registerMessage + '\n');
        ws.send(registerMessage, {mask: true});
        isWebSocketReady = true;
    }
    catch (e) {
        console.error('Failed to register messages. Error in registering message: ' + e.toString());
    }    
}


//data after receiving is sent here for processing
// in our case this function will not be used as we will not receive any action
// in raspberry pi. This is for future modification.
function handleRcvMsg(msg){
	// you have to parse the received string
    var msgObj = JSON.parse(msg);
    if (msgObj.type != "action") return; //Early return;

    var actions = msgObj.data.actions;
    var actionName = actions[0].name; 
    console.log("The received action is " + actionName);
  
    //you must know your registered actions in order to perform accordinlgy
    if (actionName.toLowerCase() == "parking_state") 
    { 
        // do something here after receiving 'parking_state'
    }
    else {
         //this loop executes if some unregistered action is received
         //so you must register every action in cloud
        console.log('Do nothing since receiving unrecognized action ' + actionName);
        return;
    }
   
}



/**
 * Send one message to ARTIK Cloud
 */
//This function is responsible for sending commands to cloud
//function sendStateToArtikCloud(parking) sends number of free parking slot to artik cloud
function sendStateToArtikCloud(parking){
    try{
        ts = ', "ts": '+getTimeMillis();
        var data = {
            "rainbowlot": parking
            //setting the parking value from argument to our cloud variable "parking_value"

            };
        var payload = '{"sdid":"'+device_id+'"'+ts+', "data": '+JSON.stringify(data)+', "cid":"'+getTimeMillis()+'"}';
        console.log('Sending payload ' + payload + '\n');
        ws.send(payload, {mask: true});
    } catch (e) {
        console.error('Error in sending a message: ' + e.toString() +'\n');
    }    
}



function exitClosePins() {
    
        console.log('Exit and destroy all pins!');
        process.exit();
    
}


start();
//exectes every time when data is received from arduino (30 sec programmed delay from arduino)
sp.on("open", function () {
    sp.on('data', function(data) {
            console.log("Serial port received data:" + data);
            //sendStateToArtikCloud(data);//free parking slot
            sendStateToArtikCloud(data);
           
    });
});

process.on('SIGINT', exitClosePins);

Arduino (sonar-sensor)

C/C++
Source code for sonar sensor interfacing using Arduino
#define echoPin1 2 // Echo Pin for sonar 1
#define trigPin1 3 // Trigger Pin for sonar 1
#define echoPin2 4 // Echo Pin for sonar 2 
#define trigPin2 5 // Trigger Pin for sonar 2
#define echoPin3 6 // Echo Pin for sonar 3
#define trigPin3 7 // Trigger Pin for sonar 3
#define echoPin4 9 // Echo Pin for sonar 4
#define trigPin4 8 // Trigger Pin for sonar 4


long duration1, distance1; // Duration used to calculate distance
long duration2, distance2;
long duration3, distance3;
long duration4, distance4; 

int count=0;
int freeSlot =0;

void setup() {
 Serial.begin (9600); // initiate serial communication to raspberry pi
 pinMode(trigPin1, OUTPUT); // trigger pin as output
 pinMode(echoPin1, INPUT);  // echo pin as input
 pinMode(trigPin2, OUTPUT);
 pinMode(echoPin2, INPUT);
 pinMode(trigPin3, OUTPUT);
 pinMode(echoPin3, INPUT);
 pinMode(trigPin4, OUTPUT);
 pinMode(echoPin4, INPUT);
 
}

void loop() {
/* The following trigPin/echoPin cycle is used to determine the
 distance of the nearest object by bouncing soundwaves off of it. */ 

/* At least 10 microsecond high level signal is required to trigger 
 * pin. 
 *               _____
 *              |     |
 * -------------!     !---------
 *         .....|10us |........
 * the module then produce eight 40KHz pulse signal and waits to receive echo
 */
 digitalWrite(trigPin1, LOW); 
 delayMicroseconds(2); 
 digitalWrite(trigPin1, HIGH);
 delayMicroseconds(10); 
 digitalWrite(trigPin1, LOW);
 // pulseIn( ) function determines a pulse width in time
 // duration of pulse is proportional to distance of obstacle
 duration1 = pulseIn(echoPin1, HIGH);

 digitalWrite(trigPin2, LOW);
 delayMicroseconds(2); 
 digitalWrite(trigPin2, HIGH);
 delayMicroseconds(10); 
 digitalWrite(trigPin2, LOW);
 duration2 = pulseIn(echoPin2, HIGH);
 
 digitalWrite(trigPin3, LOW);
 delayMicroseconds(2); 
 digitalWrite(trigPin3, HIGH);
 delayMicroseconds(10); 
 digitalWrite(trigPin3, LOW);
 duration3 = pulseIn(echoPin3, HIGH);

 digitalWrite(trigPin4, LOW);
 delayMicroseconds(2); 
 digitalWrite(trigPin4, HIGH);
 delayMicroseconds(10); 
 digitalWrite(trigPin4, LOW);
 duration4 = pulseIn(echoPin4, HIGH);
 
 //  distance = (high level timevelocity of sound (340M/S) / 2, 
 //  in centimeter = uS/58
 distance1 = duration1/58.2;
 if(distance1<10)
   distance1 = 1;
 else distance1 = 0;
 
 distance2 = duration2/58.2;
 if(distance2<10)
   distance2 = 1;
 else distance2 = 0;
 
 distance3 = duration3/58.2;
 if(distance3<10)
   distance3 = 1;
 else distance3 = 0;

 distance4 = duration4/58.2;
 if(distance4<10)
   distance4 = 1;
 else distance4 = 0;

 // add the result from all sensor to count total car
 count = distance1 + distance2 + distance3 + distance4;;

 // free slot = total slot - total car
 freeSlot = 4 - count;
 // number of total slot is sent to raspberry pi using usb
 Serial.println(freeSlot);
 // the status is updated every 30 seconds.
 delay(30000);
 freeSlot = 0;
 distance1 = 0;
 distance2 = 0;
 distance3 = 0;
 distance4 = 0;
}

Intel Edison (main.js)

JavaScript
Source code for Intel Edison to display parking information in lcd
// Libmraa is a C/C++ library with bindings to Java, Python and JavaScript
// to interface with the IO on Galileo, Edison & other platforms, 
// with a structured and sane API where port names/numbering matches the board that you are on.
var mraa = require('mraa');
// Hitachi HD44780 LCD driver for Linux boards
var lcd = require('./lcd');

var version = mraa.getVersion();
var display = new lcd.LCD(0);
// mqtt is a client library for the MQTT protocol, written in JavaScript for node.js and the browser.
var mqtt = require('mqtt');
// Node implements File I/O using simple wrappers around standard POSIX functions. 
// The Node File System (fs) module is imported using the following line
var fs = require('fs');
// mqtt connection endpoint is define in ARTIK Cloud documantation page
var PROTOCOL = 'mqtts';
var BROKER ='api.artik.cloud';
var PORT = 8883;

var URL = PROTOCOL + '://' + BROKER;
URL += ':' + PORT;
// device id and device token is used for authentication 
var deviceID = '4368e28eb8db4adfa368e5e0120932fa';
var deviceTOKEN = '655eac98350f42858e7df90cd270550a';
// use device id as username & device token as password
var requireds = { username: deviceID, password: deviceTOKEN };
var mqttConfig = { 'url': URL, 'requireds': requireds };
// Connects to the broker specified by the given url and options and returns a Client.
var client = mqtt.connect(mqttConfig.url, mqttConfig.requireds);
// topic for client
var pubTOPIC = '/v1.1/messages/'+deviceID;
// topic for subscriber
var subTOPIC = '/v1.1/actions/'+deviceID;

if (version >= 'v0.6.1') {
    console.log('mraa version (' + version + ') ok');
}
else {
    console.log('meaa version(' + version + ') is old - this code may not work');
}

// Emitted automatically on successful connection 
client.on('connect', function () {
  console.log('connected');
  // set backlight color for RGB lcd
  display.setColor(255, 255, 255);
  display.setCursor(0,0);
  display.write('Connected');
  // subscribe to the topic
  client.subscribe(subTOPIC);  
});

// Emitted when the client receives a publish packet 
// topic is topic of the received packet
// message payload of the received packet
client.on('message', function (topic, message) {
  // message is Buffer 
  // parses the received string as JSON
  var msgObj = JSON.parse(message);
  var rainbowData = msgObj.actions[0].parameters.text; 
  var indigoData = msgObj.actions[0].parameters.text2; 
  // the values then print to lcd display
  display.setCursor(0,0);
  display.write('RainbowFSlot: '+rainbowData); 
  display.setCursor(1,0);
  display.write('IndigoFrSlot: '+indigoData); 
  console.log(rainbowData);
  console.log(message.toString())
  //client.end()
});

Web Application

JavaScript
Source for web application
// real-time interactions are possible using websocket
// Notice the ws:. This is the new URL schema for WebSocket connections. 
// There is also wss: for secure WebSocket connection the same way 
// https: is used for secure HTTP connections.
// you can get it from Artik cloud documentation page
var wsUri = "wss://api.artik.cloud/v1.1/websocket?ack=true";
var device_id = "YOUR DEVICE ID HERE"; // Edison parking DEVICE ID
var device_token = "YOUR DEVICE TOKEN HERE"; //Intel Edison parking DEVICE TOKEN

var output;
var attributes_log;
var websocket;

function init() {
	// document.getElementById() write something to html page
    output = document.getElementById("output");
    attributes_log = document.getElementById("attributes_log");
    if (browserSupportsWebSockets() === false) {
		// check browser support websocket protocol or not
        writeToScreen("Sorry! your web browser does not support WebSockets. Try using Google Chrome or Firefox Latest Versions");

        var element = document.getElementById("websocketelements");
        element.parentNode.removeChild(element);

        return; //
    }
    //You open up a WebSocket connection simply by calling the WebSocket constructor
    websocket = new WebSocket(wsUri);
    //When the connection is open, function invoked automatically
    websocket.onopen = function() {		
        //writeAttributeValues('onOpen Event Fired');
        writeToScreen("Successfully connected to Parking System");
		// after connection is open, registration is required for secure data transmission
		register();
    };
    // invoked when new message received
    websocket.onmessage = function(evt) {
        onMessage(evt);
    };
    // when received error
	// You can handle any errors that occur by listening out for the error event.
    websocket.onerror = function(evt) {
        onError(evt);
    };
}

function onClose(evt) {
	// Once youre done with your WebSocket you can terminate the connection using the close() method.
    websocket.close();
    //writeAttributeValues('onClose Event Fired');
    writeToScreen("DISCONNECTED");
}

// When a message is received the message event is fired. 
function onMessage(evt) {
    writeToScreen('<span style="color: blue;">RESPONSE: ' + evt.data + '</span>');
    //writeAttributeValues('onMessage Event Fired');
	handleRcvMsg(evt.data); //data is send to the function handleRcvMsg()
}

function onError(evt) {
    writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
    //writeAttributeValues('onError Event Fired');
}

function doSend(message) {
	// To send a message through the WebSocket connection you call the send() method on your WebSocket instance
    websocket.send(message);
    //writeAttributeValues('onSend Event Fired');
    writeToScreen("SENT: " + message);
}

function writeAttributeValues(prefix) {
    var pre = document.createElement("p");
    pre.style.wordWrap = "break-word";
    pre.innerHTML = "INFO " + getCurrentDate() + " " + prefix + "<b> readyState: " + websocket.readyState + " bufferedAmount: " + websocket.bufferedAmount + "</b>";
    ;
    attributes_log.appendChild(pre);
}

function writeToScreen(message) {
    var pre = document.createElement("p");
    pre.style.wordWrap = "break-word";
    pre.innerHTML = message;
    output.appendChild(pre);
}

function getCurrentDate() {
    var now = new Date();
    var datetime = now.getFullYear() + '/' + (now.getMonth() + 1) + '/' + now.getDate();
    datetime += ' ' + now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds();
    return datetime;
}

function browserSupportsWebSockets() {
    if ("WebSocket" in window)
    {
        return true;
    }
    else
    {
        return false;
    }
}

function getTimeMillis(){
    return parseInt(Date.now().toString());
}

function register(){
    writeToScreen("Registering device on the WebSocket connection");
    try{
        var registerMessage = '{"type":"register", "sdid":"'+device_id+'", "Authorization":"bearer '+device_token+'", "cid":"'+getTimeMillis()+'"}';
        writeToScreen('Sending register message ' + registerMessage + '\n');
        websocket.send(registerMessage, {mask: true});
        isWebSocketReady = true;
		//document.getElementById("rainbow").innerHTML = "";
		//document.getElementById("rainbow").innerHTML = "Capacity:"+'<span style="color: red;">50</span> '+"Free Slot:"+'<span style="color: red;"></span>'+"50";
        //document.getElementById("indigo").innerHTML = "Capacity: 60,  Free Slot: 5";
	}
    catch (e) {
        writeToScreen('Failed to register messages. Error in registering message: ' + e.toString());
    }    
}

//data after receiving is sent here for processing
function handleRcvMsg(msg){
	// message is received as following string
	// {"actions":[{"name":"setText","parameters":{"text":"4", "text2": "5"}}]}
	// you have to parse it
    var msgObj = JSON.parse(msg);
    if (msgObj.type != "action") return; //Early return;

    var actions = msgObj.data.actions;
    var rainbowData = actions[0].parameters.text; 
	var indigoData = actions[0].parameters.text2; 
    console.log("The received action is " + actions);  
	document.getElementById("rainbow").innerHTML = "Capacity: 50,  Free Slot: "+rainbowData;
	document.getElementById("indigo").innerHTML = "Capacity: 60,  Free Slot: "+indigoData;
   
}

Android App

Java
Source code for android appication
package cloud.artik.example.hellocloud;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import cloud.artik.api.MessagesApi;
import cloud.artik.api.UsersApi;
import cloud.artik.client.ApiCallback;
import cloud.artik.client.ApiClient;
import cloud.artik.client.ApiException;
import cloud.artik.model.MessageAction;
import cloud.artik.model.MessageIDEnvelope;
import cloud.artik.model.NormalizedMessagesEnvelope;
import cloud.artik.model.UserEnvelope;

public class MessageActivity extends Activity {
    private static final String TAG = "MessageActivity";

    private static final String RDEVICE_ID = "Your Device ID";
    public static final String RKEY_ACCESS_TOKEN = "Your Device Token";  // r set
    private static final String IDEVICE_ID = "Another Device ID";
    public static final String IKEY_ACCESS_TOKEN = "Another Device Token";  // r set



    private MessagesApi rMessagesApi = null; // r set
    private MessagesApi iMessagesApi = null; // r set
    

    private String rAccessToken;    // r set
    private String iAccessToken;    // r set

    private TextView rainbowLot;
    private TextView indigoLot;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_message);

        rAccessToken = getIntent().getStringExtra(RKEY_ACCESS_TOKEN);   // r set
        iAccessToken = getIntent().getStringExtra(IKEY_ACCESS_TOKEN);   // r set

        Button getLatestMsgBtn = (Button)findViewById(R.id.getlatest_btn);

        rainbowLot = (TextView)findViewById(R.id.txtRlot);
        indigoLot = (TextView)findViewById(R.id.txtIlot);
        
        setupArtikCloudApi();

        getLatestMsgBtn.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {

                // Now get the message
                //getRainbowMsg();
                getIndigoMsg();
            }
        });
    }

    private void setupArtikCloudApi() {
        ApiClient rApiClient = new ApiClient();
        ApiClient iApiClient = new ApiClient();

        rApiClient.setAccessToken(rAccessToken);   // r set
        iApiClient.setAccessToken(iAccessToken);   // r set

        rMessagesApi = new MessagesApi(rApiClient);  // r set
        iMessagesApi = new MessagesApi(iApiClient);  // r set
    }

    private void getRainbowMsg() {
        final String tag = TAG + " getLastNormalizedMessagesAsync";
        try {
            int messageCount = 2;
            rMessagesApi.getLastNormalizedMessagesAsync(messageCount, RDEVICE_ID, null,
                    new ApiCallback<NormalizedMessagesEnvelope>() {
                        @Override
                        public void onFailure(ApiException exc, int i, Map<String, List<String>> stringListMap) {
                            processFailure(tag, exc);
                        }

                        @Override
                        public void onSuccess(NormalizedMessagesEnvelope result, int i, Map<String, List<String>> stringListMap) {
                            Log.v(tag, " onSuccess latestMessage = " + result.getData().toString());
                            updateGetResponseOnUIThread(result.getData().get(0).getMid(), result.getData().get(0).getData().toString());
                        }

                        @Override
                        public void onUploadProgress(long bytes, long contentLen, boolean done) {
                        }

                        @Override
                        public void onDownloadProgress(long bytes, long contentLen, boolean done) {
                        }
                    });

        } catch (ApiException exc) {
            processFailure(tag, exc);
        }
    }

    private void getIndigoMsg() {
        final String tag = TAG + " getLastNormalizedMessagesAsync";
        try {
            int messageCount = 1;
            iMessagesApi.getLastNormalizedMessagesAsync(messageCount, IDEVICE_ID, null,
                    new ApiCallback<NormalizedMessagesEnvelope>() {
                        @Override
                        public void onFailure(ApiException exc, int i, Map<String, List<String>> stringListMap) {
                            processFailure(tag, exc);
                        }

                        @Override
                        public void onSuccess(NormalizedMessagesEnvelope result, int i, Map<String, List<String>> stringListMap) {
                            Log.v(tag, " onSuccess latestMessage = " + result.getData().toString());
                            updateGetResponseOnUIThread(result.getData().get(0).getMid(), result.getData().get(0).getData().toString());
                        }

                        @Override
                        public void onUploadProgress(long bytes, long contentLen, boolean done) {
                        }

                        @Override
                        public void onDownloadProgress(long bytes, long contentLen, boolean done) {
                        }
                    });

        } catch (ApiException exc) {
            processFailure(tag, exc);
        }
    }

    static void showErrorOnUIThread(final String text, final Activity activity) {
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                int duration = Toast.LENGTH_LONG;
                Toast toast = Toast.makeText(activity.getApplicationContext(), text, duration);
                toast.show();
            }
        });
    }


    private void updateGetResponseOnUIThread(final String mid, final String msgData) {
        this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                String delims = "[=}.]+";
                String[] tokens = msgData.split(delims);
                //rainbowLot.setText(tokens[1]);
                indigoLot.setText(tokens[1]);
            }
        });
    }

    private void processFailure(final String context, ApiException exc) {
        String errorDetail = " onFailure with exception" + exc;
        Log.w(context, errorDetail);
        exc.printStackTrace();
        showErrorOnUIThread(context+errorDetail, MessageActivity.this);
    }

} //MessageActivity

Source Code for Smart Parking System

All the necessary code and files are included in this Github repository.

Credits

Md. Khairul Alam

Md. Khairul Alam

64 projects • 568 followers
Developer, Maker & Hardware Hacker. Currently working as a faculty at the University of Asia Pacific, Dhaka, Bangladesh.

Comments