C Team
Published © GPL3+

Visitor Counter

Count visitors in a place and publish on Losant dashboard.

IntermediateShowcase (no instructions)4 hours2,100
Visitor Counter

Things used in this project

Hardware components

Photon
Particle Photon
×1
Breadboard (generic)
Breadboard (generic)
×1
LED (generic)
LED (generic)
×1
Adafruit IR Break Beam Sensor
×2

Software apps and online services

Losant Platform
Losant Platform

Story

Read more

Schematics

Layout

Layout of the board. - Instead of IR Receivers, you could use a IR sender/receiver combined unit

Code

Code for the .INO file

C/C++
Code for the .INO file at particle.io. The file is created when you start a new project at particle.io
/*
 *  This file is a sample application, based
 *  on the IoT Prototyping Framework (IoTPF)

    This application and IoTPF is free software: you can redistribute it     and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    IoTPF is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU v3 General Public License for more details.

    Released under GNU v3

    You should have received a copy of the GNU General Public License
    along with IoTPF.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 /**
    Internet of Things Prototyping Framework IoTPF  
    @Version 1.0
    @author Dionysios Satikidid
    
    Visitor Counter (out of SmartAtmo) 2017/2018
    @version 1.0
    @author Rasid Music, Thomas Günter
*/

#include <ArduinoJson.h>                        // JSON Library for serialisation of the payload
#include "StatusLed.h"                          // Helper class, uses a led to indicate codes via a led
#include "MqttLauncher.h"                       // Wrapper for MQTT client, providing some convenience for sending sensor data

#define TTL 60                                  // Time to live for messages published to particle cloud
#define LOOP_DELAY 1000                         // Delay for repeating the loop function in ms
#define PUBLISHING_DELAY 10000                  // Delay for publishing data to cloud
#define LOSANT_BROKER "broker.losant.com"       // URL of the Losant MQTT Broker
#define DEVICE "<<losant device id>>.   "       // ID Of my Device
#define ACCESS "<<losant access key>>"          // Access Secret
#define SECRET "<<losant access secret>>"       // Access Secret
#define TOPIC "losant/<<losant device id>>/state" // Topic for Measurements

enum MotionState {no_motion, s0, s1, illegal};  // Enumeration describing the states of the motion sensor
void callback(char* topic, byte* payload        // callback method for the mqtt client
    , unsigned int length);
void isr0(void);                                // Interrupt Service Routine for motion sensor
void isr1(void);                                // Interrupt Service Routine for motion sensor

int loopCounter = 0;                            // counter for publishing mqtt message
volatile MotionState state = no_motion;         // state of the motion sensor
volatile int pers = 0;                          // persons in room
volatile long debounce0 = 0;                    // helper for debouncing motion
volatile long debounce1 = 0;                    // helper for debouncing motion
long debounce = 100;                            // value for debouncing of the motion sensor
StatusLed errorLed;                             // Status LED, used to indicate sate
MqttLauncher *mqtt;                             // mqtt wrapper to send data to losant via mqtt
float coo = 0;                                  // value for mq135 readings
MQ135 mq135(MQ135_PORT);                        // Provides access to co2 readings of mq135

   /***** Led Notification ****
    1 - state s0
    2 - state s1
    3 - illegal state
    4 - Failed sending Device Status to Losant
    *****************************/

void setup() {

    /********** Initialize Status LED ******/
    pinMode(D0, OUTPUT);
    errorLed.setLed(D0);


    /********** Initialize ISR ************/
    attachInterrupt(A0, isr0, RISING);
    attachInterrupt(A1, isr1, RISING);


    /********** Initialize MQTT Client ****/
    mqtt = new MqttLauncher(
        LOSANT_BROKER
        , 1883
        , DEVICE
        , ACCESS
        , SECRET
        , callback);


    Particle.publish("getStable/setup", "Setup done");
}

void loop() {

    if(loopCounter >= PUBLISHING_DELAY){
        loopCounter = 0;

        // adding payload
        mqtt->addPayload("pers", pers);
        //mqtt->addPayload("device", 666);

        if(!mqtt->launch(TOPIC)){
            errorLed.notify(4, 200);
        }

        pers = 0;
    }

    errorLed.notify(state, 100);

    delay(LOOP_DELAY);
    loopCounter += LOOP_DELAY;
}

void isr0(){
    if(debounce0 > millis()){
        return;
    }

    switch(state) {
        case no_motion:
            state = s0;
            return;

        case s0:
            return;

        case s1:
            pers--;
            debounce0 = millis() + debounce;
            state = no_motion;
            return;

        default:
            state = illegal;
            return;
    }
}

void isr1(){
    if(debounce1 > millis()){
        return;
    }

    switch(state) {
        case no_motion:
            state = s1;
            return;

        case s1:
            return;

        case s0:
            pers++;
            debounce1 = millis() + debounce;
            state = no_motion;
            return;

        default:
            state = illegal;
            return;
    }
}

void callback(char* topic, byte* payload, unsigned int length) { }

Status led

C/C++
We use a LED to indicate the state of the counter. This is the code for the status led.
/*
 *  This file is a sample application, based
 *  on the IoT Prototyping Framework (IoTPF)

    This application and IoTPF is free software: you can redistribute it     and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    IoTPF is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU v3 General Public License for more details.

    Released under GNU v3

    You should have received a copy of the GNU General Public License
    along with IoTPF.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 /**
    Internet of Things Prototyping Framework IoTPF  
    @Version 1.0
    @author Dionysios Satikidid
    
    Visitor Counter (out of SmartAtmo) 2017/2018
    @version 1.0
    @author Rasid Music, Thomas Günter
*/

#include "application.h"

class StatusLed {

    private:
    int led = 0;
    bool ledState = false;


    public:
    // led will blink n = code times, and toggle with the given frequency in ms
    void notify(int code, int frequency);

    // notify will use the port given in led
    void setLed(int port);

    private:
    // toggles the led and returns the given state (true, or false)
    void toggle();
};



#include "StatusLed.h"

void StatusLed::setLed(int port){
    led = port;
}

void StatusLed::notify(int code, int frequency){
    for(int i = 0; i < code * 2; i++){
        toggle();
        delay(frequency);
    }

    delay(frequency * 2);

}

void StatusLed::toggle(){
    digitalWrite(led, !ledState);
    ledState = !ledState;
}

MqttLauncher

C/C++
This is the code used to send MQTT Messages to losant.
/*
 *  This file is a sample application, based
 *  on the IoT Prototyping Framework (IoTPF)

    This application and IoTPF is free software: you can redistribute it     and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    IoTPF is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU v3 General Public License for more details.

    Released under GNU v3

    You should have received a copy of the GNU General Public License
    along with IoTPF.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 /**
    Internet of Things Prototyping Framework IoTPF  
    @Version 1.0
    @author Dionysios Satikidid
    
    Visitor Counter (out of SmartAtmo) 2017/2018
    @version 1.0
    @author Rasid Music, Thomas Günter
*/

#include <string>
#include <MQTT.h>               // MQTT Client to carry the payloat to losant
#include <ArduinoJson.h>        // JSON Library for serialisation of the payload

#define JSON_BUFFER_SIZE 255    // Size of the Json buffer. This affects the total length of the payload of MQTT messages

class MqttLauncher {

    private:
        String client;
        String device;
        String key;
        String secret;
        int port;
        String url;
        MQTT* mqttClient;
        StaticJsonBuffer<JSON_BUFFER_SIZE> payload;
        JsonObject& root = payload.createObject();
        JsonObject& data = root.createNestedObject("data");

    public:
        // Constructor
        MqttLauncher(String url, int port, String device, String key, String secret ,void (*_callback)(char*,uint8_t*,unsigned int));

        // adds a key val pair to the data section
        void addPayload(String key, int val);
        void addPayload(String key, float val);
        void addPayload(String key, String val);


        // sends the mqtt message, the data section will be deleted
        bool launch(String topic);
};


#include "MqttLauncher.h"

MqttLauncher::MqttLauncher(
        String _url
        , int _port
        , String _device
        , String _key
        , String _secret
        ,  void (*_callback)(char* topic, byte* payload, unsigned int length)) {
    device = _device;
    key = _key;
    secret = _secret;
    url = _url;
    port = _port;

    // stack overflow magic https://stackoverflow.com/questions/7352099/stdstring-to-char
    // without this, call of the MQTT constructor is ambigous
    char *broker = &url[0u];
    mqttClient = new MQTT(broker, _port, _callback);
}

bool MqttLauncher::launch(String topic){
    char buffer[JSON_BUFFER_SIZE];
    root.printTo(buffer, JSON_BUFFER_SIZE);

    mqttClient->connect(device, key, secret);

    if(mqttClient->isConnected()){
        mqttClient->publish(topic, buffer);
        mqttClient->disconnect();

        payload.clear();
        JsonObject& root = payload.createObject();
        JsonObject& data = root.createNestedObject("data");

        return true;
    }else{
        return false;
    }
}

void MqttLauncher::addPayload(String key, int val){
    char *_key = &key[0u];
    data[_key] = val;
}

void MqttLauncher::addPayload(String key, float val){
    char *_key = &key[0u];
    data[_key] = val;
}

void MqttLauncher::addPayload(String key, String val){
    char *_key = &key[0u];
    char *_val = &val[0u];
    data[_key] = _val;
}

Workflow to import

JSON
This is the workflow to import it to Losant. Please note, that you have to set tables and devices before it will work.
{"globals":[],"triggers":[{"config":{},"outputIds":[["bnmWn8SW0y"]],"key":"5a58aa9d6061390006c792b7","type":"deviceId","meta":{"category":"trigger","name":"deviceIdsTags","label":"Device: State","x":300,"y":80,"uiId":"Ko0~1m5ZUR","description":""}}],"nodes":[{"type":"DataTableUpdateRowNode","meta":{"category":"data","name":"update-table-row","label":"Table: Update Row","x":300,"y":540,"description":""},"config":{"dataTableIdTemplate":"5a57c6de261e0b0007edfc3b","rowIdTemplate":"{{data.tablerow.items.0.id}}","dataMethod":"individualFields","resultPath":"","rowFields":[{"columnTemplate":"total","valueTemplate":"{{data.value.new_total}}"}]},"id":"MYnPZFKh9U","outputIds":[["eF5CJbvxU5"]]},{"type":"DataTableQueryNode","meta":{"category":"data","name":"get-table-rows","label":"Table: Get Rows","x":300,"y":220,"queryMode":"$or","description":""},"config":{"dataTableIdTemplate":"5a57c6de261e0b0007edfc3b","sortColumnTemplate":"","sortDirectionTemplate":"","limitTemplate":"","offsetTemplate":"","resultPath":"data.tablerow","queryTemplate":"{\"$or\":[{\"device\":{\"$eq\":\"{{deviceName}}\"}}]}"},"outputIds":[["8XDiCveUXB"]],"id":"bnmWn8SW0y"},{"type":"MathNode","meta":{"category":"logic","name":"math","label":"Math","x":300,"y":380,"description":""},"config":{"statements":[{"expression":"{{data.tablerow.items.0.total}} + {{data.pers}}","resultPath":"data.value.new_total"}]},"id":"8XDiCveUXB","outputIds":[["MYnPZFKh9U"]]},{"type":"DeviceChangeStateNode","meta":{"category":"output","name":"device-state","label":"Device State","x":300,"y":740,"description":""},"config":{"deviceIdTemplateType":"stringTemplate","timeSourceType":"payloadTime","attrDataMethod":"individualFields","deviceId":"5a58add46061390006c792b8","attrInfos":[{"key":"total","valueTemplate":"{{data.value.new_total}}"}]},"id":"eF5CJbvxU5","outputIds":[]}],"name":"VisitorCounter","enabled":true,"description":"","applicationId":"59fc4cc658a69b000749f317","_type":"flow","_exportDate":"2018-01-22T13:29:41.861Z"}

Credits

C Team

C Team

2 projects • 0 followers

Comments