Mohd Islam
Published

A Complete IoT Solution Framework

The project utalises RF MCUs to communicate sensor data to cloud gateway. The sensor data collected is then visualized on an IoT dashboard.

IntermediateFull instructions provided5 days1,190
A Complete IoT Solution Framework

Things used in this project

Story

Read more

Schematics

Relay Control Circuit

Relay Circuit

Code

RF_Moisture_Sensor1_Node

C/C++
This is the sensor Node with resistive moisture sensor
// The AIR430BoostFCC library uses the SPI library internally. Energia does not
// copy the library to the output folder unless it is referenced here.
// The order of includes is also important due to this fact.

#include <SPI.h>
#include <AIR430BoostFCC.h>
#include <aJSON.h>
#include <LCD_Launchpad.h>
#include <Filter.h>



// -----------------------------------------------------------------------------
/**
 *  Global data
 */
const char analogPin = A7;



const char* mySensor = "M1";//M1 = Moisture Sensor 1 in short






LCD_LAUNCHPAD myLCD;

// -----------------------------------------------------------------------------
// Main

// Simple function for scrolling messages across the on-board LCD
void scrollText(String text)
{
  Serial.println("System Initialising");
  myLCD.displayText(text);
  Serial.println(text);
  delay(400);
  while(text != ""){
    myLCD.clear();
    text = text.substring(1);
    Serial.println(text);
    myLCD.displayText(text);
    delay(175);
  }
}

// SETUP function for sketch
void setup()
{
  // Setup serial for debug printing.
  Serial.begin(9600);
  Serial.println("\n");




  // The radio library uses the SPI library internally, this call initializes
  // SPI/CSn and GDO0 lines. Also setup initial address, channel, and TX power.
  Radio.begin(0x01, CHANNEL_1, POWER_MAX);

  // Configure the on-board LCD of the MSP430FR6989 LaunchPad
  myLCD.init();

  // Print welcome messages to the LCD screen
  //String welcome = "Hello "+String(myName);
  //scrollText(welcome);

  // Print sensor type to the LCD screen
  String sensorType = String("Moisture Sensor1");
  scrollText(sensorType);

  // Configure RED_LED, which will be used for visual notification of RF TX
  pinMode(GREEN_LED, OUTPUT);
  digitalWrite(GREEN_LED, LOW);   // set the LED off
  Serial.println("Setup Complete. Starting Radio");
}

// LOOP function for sketch
void loop()
{
  //Blink LED & TX segment on LCD to signify start of new sensor reading + RF TX
  digitalWrite(GREEN_LED, HIGH);
  myLCD.showSymbol(LCD_SEG_TX, 1);

  //***Exponential Filtering.*** Initialise all the readings to 0:

 ExponentialFilter<float>FilteredData(40, 0);
 int RawData = analogRead(analogPin);
  FilteredData.Filter(RawData);
  int SmoothData = FilteredData.Current();





  // Encode sensor readings into JSON
  /*Usual Desired JSON encoded format:
  {
    "d":{
    "d":{
      "Name":"MOhd",
      "Sensor":"Moisture",
      "Data": 1234
    }
  }
  but in this case I avoided this format as only 60 byte max can be transferred over RF.
  Therefore I have available space for addition sensor data.We can always add more detail to
  the Raw data when in cloud.
  */

  aJsonObject *msg = aJson.createObject();
    //aJsonObject *d = aJson.createObject();
    //aJson.addItemToObject(msg, "d", d);

    aJson.addStringToObject(msg, "Arafat", mySensor);//s represents sensor in short
    //int sensorValue = average;
    aJson.addNumberToObject(msg, "D",  SmoothData);// D2 represents data from moisture sensor 2 in short.

  // Typecast JSON message to char array, delete JSON object, then send via via RF
  char* payload = aJson.print(msg);
  aJson.deleteItem(msg);
  Radio.transmit(ADDRESS_BROADCAST, (uint8_t*)payload, 60);

  // Print latest sensor readings to LCD
  myLCD.displayText("    ");
  myLCD.displayText(String( SmoothData));

  // Print JSON-encoded payload to terminal, then free char array
  Serial.print("TX (DATA): ");
  Serial.println(payload);
  free(payload);

  // Transmission success! Toggle off LED & clear TX segment on LCD
  digitalWrite(GREEN_LED, LOW);
  myLCD.showSymbol(LCD_SEG_TX, 0);

  // Go to LPM3 for 1 second
  //sleepSeconds(1);
  delay(250);
}

RF_Moisture_Sensor2_Node

C/C++
This node has the capacitive sensor connected with it
// The AIR430BoostFCC library uses the SPI library internally. Energia does not
// copy the library to the output folder unless it is referenced here.
// The order of includes is also important due to this fact.

#include <SPI.h>
#include <AIR430BoostFCC.h>
#include <aJSON.h>
#include <LCD_Launchpad.h>
#include <Filter.h>
// -----------------------------------------------------------------------------
/**
 *  Global data
 */
const char analogPin = A7;

const char* mySensor = "M2";


LCD_LAUNCHPAD myLCD;

// -----------------------------------------------------------------------------
// Main

// Simple function for scrolling messages across the on-board LCD
void scrollText(String text)
{
  Serial.println("System Initialising");
  myLCD.displayText(text);
  Serial.println(text);
  delay(400);
  while(text != ""){
    myLCD.clear();
    text = text.substring(1);
    Serial.println(text);
    myLCD.displayText(text);
    delay(175);
  }
}

// SETUP function for sketch
void setup()
{
  // Setup serial for debug printing.
  Serial.begin(9600);
  Serial.println("\n");




  // The radio library uses the SPI library internally, this call initializes
  // SPI/CSn and GDO0 lines. Also setup initial address, channel, and TX power.
  Radio.begin(0x01, CHANNEL_1, POWER_MAX);

  // Configure the on-board LCD of the MSP430FR6989 LaunchPad
  myLCD.init();

  // Print welcome messages to the LCD screen
  //String welcome = "Hello "+String(myName);
  //scrollText(welcome);

  // Print sensor type to the LCD screen
  String sensorType = String("Moisture Sensor2");
  scrollText(sensorType);

  // Configure RED_LED, which will be used for visual notification of RF TX
  pinMode(GREEN_LED, OUTPUT);
  digitalWrite(GREEN_LED, LOW);   // set the LED off
  Serial.println("Setup Complete. Starting Radio");
}

// LOOP function for sketch
void loop()
{
  //Blink LED & TX segment on LCD to signify start of new sensor reading + RF TX
  digitalWrite(GREEN_LED, HIGH);
  myLCD.showSymbol(LCD_SEG_TX, 1);

  //***Exponential Filtering.*** Initialise all the readings to 0:

 ExponentialFilter<float>FilteredData(40, 0);
 int RawData = analogRead(analogPin);
  FilteredData.Filter(RawData);
  int SmoothData = FilteredData.Current();



  // Encode sensor readings into JSON
  /*Usual Desired JSON encoded format:
  {
    "d":{
    "d":{
      "Name":"MOhd",
      "Sensor":"Moisture",
      "Data": 1234
    }
  }
  but in this case I avoided this format as only 60 byte max can be transferred over RF.
  Therefore I have available space for addition sensor data.We can always add more detail to the Raw data when in cloud.
  */

  aJsonObject *msg = aJson.createObject();
  //aJsonObject *d = aJson.createObject();
  //aJson.addItemToObject(msg, "d", d);

  aJson.addStringToObject(msg, "Arafat", mySensor);//s represents sensor in short
  //int sensorValue = average;
  aJson.addNumberToObject(msg, "D",  SmoothData);// D2 represents data from moisture sensor 2 in short.

  // Typecast JSON message to char array, delete JSON object, then send via via RF
  char* payload = aJson.print(msg);
  aJson.deleteItem(msg);
  Radio.transmit(ADDRESS_BROADCAST, (uint8_t*)payload, 60);

  // Print latest sensor readings to LCD
  myLCD.displayText("    ");
  myLCD.displayText(String( SmoothData));

  // Print JSON-encoded payload to terminal, then free char array
  Serial.print("TX (DATA): ");
  Serial.println(payload);
  free(payload);

  // Transmission success! Toggle off LED & clear TX segment on LCD
  digitalWrite(GREEN_LED, LOW);
  myLCD.showSymbol(LCD_SEG_TX, 0);

  // Go to LPM3 for 1 second
  //sleepSeconds(1);
  delay(300);
}

ActuatorControl

C/C++
#include <SPI.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <aJSON.h>


// -----------------------------------------------------------------------------
/**
 *  Global data
*/


const char* myName = "Arafat";
const char* myActuator = "Pump";
const char pumpStatus = 19;
const char pumpControl = 18;
const char pumpRelay1 = 17;

char ssid[] = "maaislam";          // LenovoWIFI your network name also called SSID
char password[] = "123asdfgh";       // your network password
char server[] = "broker.hivemq.com";  // MQTTServer to use


WiFiClient wifiClient;              // Connecting to MQTT broker via Wi-Fi

PubSubClient client(server, 1883, callback, wifiClient);  // Initialize MQTT client



void callback(char* topic, byte* payload, unsigned int length) {
    if ((char)payload[0] == '1') {

                    digitalWrite(pumpRelay1, HIGH);// Turn the Relay on (Note that LOW is the voltage level
                    digitalWrite(pumpControl, HIGH);

                  } else {
                      //digitalWrite(pumpRelay,LOW);  // Turn the Relay off by making the voltage HIGH
                    digitalWrite(pumpControl, LOW);
                    digitalWrite(pumpRelay1, LOW);
                                      }
     Serial.print("Message arrived in topic: ");
       Serial.println(topic);
delay(250);
       Serial.print("Message:");
       for (int i = 0; i < length; i++) {
         Serial.println((char)payload[i]);
       }

       Serial.println();
       // Switch on the LED if an 1 was received as first character
       mqttPublish();
}

void mqttSubscribe()
{

    // Reconnect if the connection was lost
          if (!client.connected()) {
            Serial.println("Disconnected. Reconnecting....");
            client.connect("123asdfg_gateway2");

              if(client.subscribe("maaislamPumpControl")) {
                Serial.println("Subscription successfull");
              }
            }


          // Check if any message were received
          // on the subscribed topic
}
void mqttPublish()
{

    // Encode Switch status into JSON before publishing

    /* JSON encoded format sample:
      {
        "d":{
        "d":{
          "Name":"MOhd",
          "Sensor":"Moisture",
          "Data": 1234
        }
      }*/
                     aJsonObject *msg = aJson.createObject();
                     aJsonObject *d = aJson.createObject();
                     aJson.addItemToObject(msg, "d", d);
                     aJson.addStringToObject(d, "Name", myName);
                     aJson.addStringToObject(d, "Actuator", myActuator);
                     int switchState = digitalRead(pumpStatus);
                     aJson.addNumberToObject(d, "Data", switchState);

     // Typecast JSON message to char array and delete JSON object
                           char* payload = aJson.print(msg);

    //MQTT Publish
           if ( client.publish("maaislamPumpStatus",(char*)payload))
           {
            digitalWrite(YELLOW_LED, HIGH);
            Serial.println("MQTT Publish success!");
            digitalWrite(YELLOW_LED, LOW);
            //Serial print payload
                    Serial.println(payload);
                    free(payload);
           }
           else
             {
               Serial.println("MQTT Publish failed!");
             }
           aJson.deleteItem(msg);
}

void PinLedSetup()
{
//pin mode setup
    pinMode(pumpRelay1, OUTPUT);
    digitalWrite(pumpRelay1, LOW);

    pinMode(pumpStatus, INPUT);
    digitalWrite(pumpStatus, LOW);

    pinMode(pumpControl, OUTPUT);
    digitalWrite(pumpControl, LOW);



    pinMode(RED_LED, OUTPUT);     // RED LED Notifier for MQTT Receiption
    digitalWrite(RED_LED, LOW);

    pinMode(GREEN_LED, OUTPUT);     // GREEN LED Notifier for Wi-Fi connected
    digitalWrite(GREEN_LED, LOW);

    pinMode(YELLOW_LED, OUTPUT);    // YELLOW LED Notifier for MQTT Pub successful
    digitalWrite(YELLOW_LED, LOW);

}
//
// -----------------------------------------------------------------------------
// Main

void setup()
{

    PinLedSetup();



  // Setup serial for debug printing.
    Serial.begin(115200);
    Serial.print("Attempting to connect to Network named: ");

    // print the network name (SSID);
    Serial.println(ssid);

    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    WiFi.begin(ssid, password);
    while ( WiFi.status() != WL_CONNECTED) {

        // print dots while we wait to connect
      Serial.print(".");
      delay(300);}

  // Connected to Wi-Fi!
  Serial.println("\nYou're connected to the network");
  Serial.println("Waiting for an ip address");

  // Wait for IP Address
  while (WiFi.localIP() == INADDR_NONE) {

      // print dots while we wait for an ip addresss
    Serial.print(".");
    delay(300);
  }
  Serial.println("\nIP Address obtained");

  // We are connected and have an IP address. Print the WiFi status.
  printWifiStatus();

}

void loop()
{
    mqttSubscribe();



    client.poll();
    delay(250);
}

void printWifiStatus() {

  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:

  digitalWrite(GREEN_LED, HIGH);  // Connected to WiFi LED
  //delay(1000);
}

LCD Library (LCD_Launchpad.cpp)

C/C++
LCD_Launchpad.cpp
/* --COPYRIGHT--,BSD
 * Copyright (c) 2015, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * --/COPYRIGHT--*/
/*******************************************************************************
 *
 * LCD_Launchpad.cpp
 *
 * Hardware abstraction layer for the FH-1138P Segmented LCD
 * on MSP-EXP430FR6989 and MSP-EXP430FR4133
 *
 * February 2015
 * E. Chen
 *
 * June 2015 StefanSch: Adopted for Energia
 *
 ******************************************************************************/

#include "LCD_Launchpad.h"
#include "string.h"


//***** Defines ***************************************************************

// Define word access definitions to LCD memories
#ifndef LCDMEMW
#define LCDMEMW    ((int*) LCDMEM) /* LCD Memory (for C) */
#endif

// Number of character positions in the display
#define LCD_NUM_CHAR                6

#if defined(__MSP430_HAS_LCD_C__)
//Change based on LCD Memory locations
#define pos1 9   /* Digit A1 begins at S18 */
#define pos2 5   /* Digit A2 begins at S10 */
#define pos3 3   /* Digit A3 begins at S6  */
#define pos4 18  /* Digit A4 begins at S36 */
#define pos5 14  /* Digit A5 begins at S28 */
#define pos6 7   /* Digit A6 begins at S14 */


// Memory locations for LCD characters
const uint8_t digit_loc[ LCD_NUM_CHAR ] =
{
       pos1,                                                                    // Position 1 = Digit A1
       pos2,                                                                    // Position 2 = Digit A2
       pos3,                                                                    // Position 3 = Digit A3
       pos4,                                                                    // Position 4 = Digit A4
       pos5,                                                                    // Position 5 = Digit A5
       pos6                                                                     // Position 6 = Digit A6
};


const uint8_t symbol_loc[] [2] =
{
    {   2,   0x01},   //  LCD_SEG_MARK,
    {   2,   0x02},   //  LCD_SEG_R,
    {   2,   0x04},   //  LCD_SEG_HEART,
    {   2,   0x08},   //  LCD_SEG_CLOCK,
    {   4,   0x01},   //  LCD_SEG_DOT3,
    {   4,   0x04},   //  LCD_SEG_RADIO,
    {   6,   0x01},   //  LCD_SEG_DOT2,
    {   6,   0x04},   //  LCD_SEG_COLON2,
    {   8,   0x01},   //  LCD_SEG_RX,
    {   8,   0x04},   //  LCD_SEG_TX,
    {  10,   0x01},   //  LCD_SEG_DOT1,
    {  10,   0x04},   //  LCD_SEG_MINUS1,
    {  13,   0x10},   //  LCD_SEG_BAT_POL,
    {  13,   0x20},   //  LCD_SEG_BAT1,
    {  13,   0x40},   //  LCD_SEG_BAT3,
    {  13,   0x80},   //  LCD_SEG_BAT5,
    {  15,   0x01},   //  LCD_SEG_DOT5,
    {  15,   0x04},   //  LCD_SEG_DEG5,
    {  17,   0x10},   //  LCD_SEG_BAT_ENDS,
    {  17,   0x20},   //  LCD_SEG_BAT0,
    {  17,   0x40},   //  LCD_SEG_BAT2,
    {  17,   0x80},   //  LCD_SEG_BAT4,
    {  19,   0x01},   //  LCD_SEG_DOT4,
    {  19,   0x04},   //  LCD_SEG_COLON4,
};

// LCD memory map for numeric digits
const char digit[10][2] =
{
    {0xFC, 0x28},  /* "0" LCD segments a+b+c+d+e+f+k+q */
    {0x60, 0x20},  /* "1" */
    {0xDB, 0x00},  /* "2" */
    {0xF3, 0x00},  /* "3" */
    {0x67, 0x00},  /* "4" */
    {0xB7, 0x00},  /* "5" */
    {0xBF, 0x00},  /* "6" */
    {0xE4, 0x00},  /* "7" */
    {0xFF, 0x00},  /* "8" */
    {0xF7, 0x00}   /* "9" */
};

// LCD memory map for uppercase letters
const char alphabetBig[26][2] =
{
    {0xEF, 0x00},  /* "A" LCD segments a+b+c+e+f+g+m */
    {0xF1, 0x50},  /* "B" */
    {0x9C, 0x00},  /* "C" */
    {0xF0, 0x50},  /* "D" */
    {0x9F, 0x00},  /* "E" */
    {0x8F, 0x00},  /* "F" */
    {0xBD, 0x00},  /* "G" */
    {0x6F, 0x00},  /* "H" */
    {0x90, 0x50},  /* "I" */
    {0x78, 0x00},  /* "J" */
    {0x0E, 0x22},  /* "K" */
    {0x1C, 0x00},  /* "L" */
    {0x6C, 0xA0},  /* "M" */
    {0x6C, 0x82},  /* "N" */
    {0xFC, 0x00},  /* "O" */
    {0xCF, 0x00},  /* "P" */
    {0xFC, 0x02},  /* "Q" */
    {0xCF, 0x02},  /* "R" */
    {0xB7, 0x00},  /* "S" */
    {0x80, 0x50},  /* "T" */
    {0x7C, 0x00},  /* "U" */
    {0x0C, 0x28},  /* "V" */
    {0x6C, 0x0A},  /* "W" */
    {0x00, 0xAA},  /* "X" */
    {0x00, 0xB0},  /* "Y" */
    {0x90, 0x28}   /* "Z" */
};

LCD_LAUNCHPAD::LCD_LAUNCHPAD(void) {
}

void LCD_LAUNCHPAD::init()
{
     LCDCCTL0 &= ~LCDON;
     LCDCCTL0 = (LCDMX0 | LCDMX1
                    | LCDLP | LCDSON | LCDDIV_0 | LCDPRE_4);

     LCDCPCTL0 |= 0xFFFC;
     LCDCPCTL1 |= 0xFC3F;
     LCDCPCTL2 |= 0x0FFF;

    LCDCCTL0 &= ~LCDON;
    LCDCVCTL &= ~(VLCDEXT | LCDREXT | LCDEXTBIAS |R03EXT);


    // Set VLCD voltage to 3.20v
    LCDCVCTL &= ~VLCD_15;

    LCDCVCTL |= VLCD3;

    // Enable charge pump and select internal reference for it
    LCDCVCTL |= LCDCPEN;
    LCDCVCTL &= ~VLCDREF_3;

    LCDCVCTL |= VLCDREF_0;

    LCDCCPCTL &= ~(LCDCPCLKSYNC);
    LCDCCPCTL &= ~(LCDCPDIS7 | LCDCPDIS6 | LCDCPDIS5
                    | LCDCPDIS4 | LCDCPDIS3 |
                    LCDCPDIS2 | LCDCPDIS1 |
                    LCDCPDIS0);

    LCDCCPCTL |= LCDCPCLKSYNC | 0;

    // Clear LCD memory
    LCDCMEMCTL |= LCDCLRM;

    //Turn LCD on
     LCDCCTL0 |= LCDON;
  //   //Serial.println("HERE!");
}
#endif /* defined(__MSP430_HAS_LCD_C__) */

#if defined(__MSP430_HAS_LCD_E__)
//Change based on LCD Memory locations
#define pos1 4   /* Digit A1 begins at S8 */
#define pos2 6   /* Digit A2 begins at S12 */
#define pos3 8   /* Digit A3 begins at S16  */
#define pos4 10  /* Digit A4 begins at S20 */
#define pos5 2   /* Digit A5 begins at S4 */
#define pos6 18  /* Digit A6 begins at S36 */



// Memory locations for LCD characters
const uint8_t digit_loc[ LCD_NUM_CHAR ] =
{
       pos1,                                                                    // Position 1 = Digit A1
       pos2,                                                                    // Position 2 = Digit A2
       pos3,                                                                    // Position 3 = Digit A3
       pos4,                                                                    // Position 4 = Digit A4
       pos5,                                                                    // Position 5 = Digit A5
       pos6                                                                     // Position 6 = Digit A6
};


const uint8_t symbol_loc[] [2] =
{
    {  12,   0x01},   //  LCD_SEG_MARK,
    {  12,   0x02},   //  LCD_SEG_R,
    {  12,   0x04},   //  LCD_SEG_HEART,
    {  12,   0x08},   //  LCD_SEG_CLOCK,
    {   9,   0x01},   //  LCD_SEG_DOT3,
    {   9,   0x04},   //  LCD_SEG_RADIO,
    {  10,   0x01},   //  LCD_SEG_DOT2,
    {  10,   0x04},   //  LCD_SEG_COLON2,
    {  19,   0x01},   //  LCD_SEG_RX,
    {  19,   0x04},   //  LCD_SEG_TX,
    {   5,   0x01},   //  LCD_SEG_DOT1,
    {   5,   0x04},   //  LCD_SEG_MINUS1,
    {  12,   0x10},   //  LCD_SEG_BAT_POL,
    {  12,   0x20},   //  LCD_SEG_BAT1,
    {  12,   0x40},   //  LCD_SEG_BAT3,
    {  12,   0x80},   //  LCD_SEG_BAT5,
    {   3,   0x01},   //  LCD_SEG_DOT5,
    {   3,   0x04},   //  LCD_SEG_DEG5,
    {  13,   0x01},   //  LCD_SEG_BAT_ENDS,
    {  13,   0x02},   //  LCD_SEG_BAT0,
    {  13,   0x04},   //  LCD_SEG_BAT2,
    {  13,   0x08},   //  LCD_SEG_BAT4,
    {  11,   0x01},   //  LCD_SEG_DOT4,
    {  11,   0x04},   //  LCD_SEG_COLON4,
};

// LCD memory map for numeric digits
const char digit[10][2] =
{
    {0xFC, 0x28},  /* "0" LCD segments a+b+c+d+e+f+k+q */
    {0x60, 0x20},  /* "1" */
    {0xDB, 0x00},  /* "2" */
    {0xF3, 0x00},  /* "3" */
    {0x67, 0x00},  /* "4" */
    {0xB7, 0x00},  /* "5" */
    {0xBF, 0x00},  /* "6" */
    {0xE4, 0x00},  /* "7" */
    {0xFF, 0x00},  /* "8" */
    {0xF7, 0x00}   /* "9" */
};

// LCD memory map for uppercase letters
const char alphabetBig[26][2] =
{
    {0xEF, 0x00},  /* "A" LCD segments a+b+c+e+f+g+m */
    {0xF1, 0x50},  /* "B" */
    {0x9C, 0x00},  /* "C" */
    {0xF0, 0x50},  /* "D" */
    {0x9F, 0x00},  /* "E" */
    {0x8F, 0x00},  /* "F" */
    {0xBD, 0x00},  /* "G" */
    {0x6F, 0x00},  /* "H" */
    {0x90, 0x50},  /* "I" */
    {0x78, 0x00},  /* "J" */
    {0x0E, 0x22},  /* "K" */
    {0x1C, 0x00},  /* "L" */
    {0x6C, 0xA0},  /* "M" */
    {0x6C, 0x82},  /* "N" */
    {0xFC, 0x00},  /* "O" */
    {0xCF, 0x00},  /* "P" */
    {0xFC, 0x02},  /* "Q" */
    {0xCF, 0x02},  /* "R" */
    {0xB7, 0x00},  /* "S" */
    {0x80, 0x50},  /* "T" */
    {0x7C, 0x00},  /* "U" */
    {0x0C, 0x28},  /* "V" */
    {0x6C, 0x0A},  /* "W" */
    {0x00, 0xAA},  /* "X" */
    {0x00, 0xB0},  /* "Y" */
    {0x90, 0x28}   /* "Z" */
};

LCD_LAUNCHPAD::LCD_LAUNCHPAD(void) {
}

void LCD_LAUNCHPAD::init()
{
    LCDCTL0 &= ~LCDON;
    LCDPCTL0 |= 0xFFFF;
    LCDPCTL1 |= 0x07FF;
    LCDPCTL2 |= 0x00F0;

    LCDCTL0 = (LCDMX0 | LCDMX1 | LCDSSEL_0
                   | LCDLP | LCDSON | LCDDIV_2);

    // LCD Operation - Mode 3, internal 3.02v, charge pump 256Hz
    LCDVCTL = (LCDREFEN| LCDCPEN | VLCD_6 |
               LCDCPFSEL3 | LCDCPFSEL2 | LCDCPFSEL1 | LCDCPFSEL0);

    // Clear LCD memory
    LCDMEMCTL |= LCDCLRM | LCDCLRBM;

    // Configure COMs and SEGs
    // L0 = COM0, L1 = COM1, L2 = COM2, L3 = COM3
    //LCD_E_setPinAsCOM( LCD_E_BASE, LCD_E_SEGMENT_LINE_0,   );
    //LCD_E_setPinAsCOM( LCD_E_BASE, LCD_E_SEGMENT_LINE_1, LCD_E_MEMORY_COM1 );
    //LCD_E_setPinAsCOM( LCD_E_BASE, LCD_E_SEGMENT_LINE_2, LCD_E_MEMORY_COM2 );
    //LCD_E_setPinAsCOM( LCD_E_BASE, LCD_E_SEGMENT_LINE_3, LCD_E_MEMORY_COM3 );
    LCDM0W = 0x8421;
    LCDBM0W = 0x8421;

    // Select to display main LCD memory
    LCDMEMCTL &= ~LCDDISP;
    //LCDMEMCTL |= 0;

    // Turn blinking features off
    LCDBLKCTL &= ~(LCDBLKPRE2 | LCDBLKPRE1 | LCDBLKPRE0 | LCDBLKMOD_3);
    LCDBLKCTL |= (LCDBLKPRE2 | LCDBLKMOD_0);

    //Turn LCD on
    LCDCTL0 |= LCDON;
}
#endif /* defined(__MSP430_HAS_LCD_E__) */

/*
 * Display input string across LCD screen
 */
void LCD_LAUNCHPAD::displayText(String s)
{
    LCD_LAUNCHPAD::displayText(s, 0);
}

void LCD_LAUNCHPAD::displayText(String s, char pos)
{
    int length = s.length();
    int i;
    for (i=0; i<pos; i++)
    {
        showChar(' ', i);
    }
    for (i=pos; i<length; i++)
    {
        showChar(s.charAt(i-pos), i);
    }


}

void LCD_LAUNCHPAD::displayText(char *s, char pos)
{
    int length = strlen(s);
    int i;
    for (i=0; i<pos; i++)
    {
        showChar(' ', i);
    }
    for (i=pos; i<length; i++)
    {
        showChar(s[i-pos], i);
    }
}


/*
 * Scrolls input string across LCD screen from left to right
 */
void LCD_LAUNCHPAD::displayScrollText(char *s, unsigned int wait)
{
    int length = strlen(s);
    int i;
    int x = 5;
    char buffer[] = "      ";
    for (i=0; i<length+7; i++)
    {
        int t;
        for (t=0; t<6; t++)
            buffer[t] = ' ';
        int j;
        for (j=0; j<length; j++)
        {
            if (((x+j) >= 0) && ((x+j) < 6))
                buffer[x+j] = s[j];
        }
        x--;

        showChar(buffer[0], 0);
        showChar(buffer[1], 1);
        showChar(buffer[2], 2);
        showChar(buffer[3], 3);
        showChar(buffer[4], 4);
        showChar(buffer[5], 5);

        delay(wait);
    }
}


size_t LCD_LAUNCHPAD::write(uint8_t c) {
    static char position = 0;
    if (c == '\n') {position = 0; return (c);}
    if (c == '\r') {position = 0; return (c);}
    if (position >= LCD_NUM_CHAR) position = 0;
    LCD_LAUNCHPAD::showChar(c, position++);
    return (c);
}

/*
 * Displays input character at given LCD digit/position
 * Only spaces, numeric digits, and uppercase letters are accepted characters
 */
void LCD_LAUNCHPAD::showChar(char c, int position)
{
    position = digit_loc[position];

    if (c >= 0 && c <= 9) c+= '0';
    if (c >= 'a' && c <= 'z') c-= ('a' - 'A');
    if (c == ' ')
    {
        // Display space
        LCDMEM[position] = 0;
        LCDMEM[position+1] = 0;
    }
    else if (c >= '0' && c <= '9')
    {
        // Display digit
        LCDMEM[position] = digit[c-48][0];
        LCDMEM[position+1] = digit[c-48][1];
    }
    else if (c >= 'A' && c <= 'Z')
    {
        // Display alphabet
        LCDMEM[position] = alphabetBig[c-65][0];
        LCDMEM[position+1] = alphabetBig[c-65][1];
    }
    else
    {
        // Turn all segments on if character is not a space, digit, or uppercase letter
        LCDMEM[position] = 0xFF;
        LCDMEM[position+1] = 0xFF;
    }
}

/*
 * Displays the given Symbol
 */
void LCD_LAUNCHPAD::showSymbol(char symbol, int status)
{
    if (status)
        LCDMEM[symbol_loc[symbol][0]] |= symbol_loc[symbol][1]; // switch on
    else
        LCDMEM[symbol_loc[symbol][0]] &= ~symbol_loc[symbol][1]; // switch off
}
/*
 * Clears memories to all 6 digits on the LCD
 */
void LCD_LAUNCHPAD::clear()
{
#if defined(__MSP430_HAS_LCD_C__)
    LCDCMEMCTL |= (LCDCLRM|LCDCLRBM);
#endif /* defined(__MSP430_HAS_LCD_C__) */
#if defined(__MSP430_HAS_LCD_E__)
    LCDMEMCTL |= (LCDCLRM|LCDCLRBM);
    LCDM0W = 0x8421;
    LCDBM0W = 0x8421;
#endif /* defined(__MSP430_HAS_LCD_E__) */
}

Node Red Backend

JavaScript
[{"id":"2e2bc85.6e69438","type":"tab","label":"SensorDataManipulation","disabled":false,"info":""},{"id":"a74037fd.22229","type":"tab","label":"Pump_Control","disabled":false,"info":""},{"id":"8e39dbe1.c473b","type":"tab","label":"Weather Control (Future Dev.)","disabled":false,"info":""},{"id":"f4aa86c7.144588","type":"mqtt-broker","z":"","name":"","broker":"broker.hivemq.com","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"d083b646.6dc7d8","type":"ui_base","theme":{"name":"theme-custom","lightTheme":{"default":"#0094CE","baseColor":"#0094CE","baseFont":"-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif","edited":true,"reset":false},"darkTheme":{"default":"#097479","baseColor":"#097479","baseFont":"-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif","edited":true,"reset":false},"customTheme":{"name":"MY Custom Theme","default":"#4B7930","baseColor":"#2099d8","baseFont":"-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif","reset":false},"themeState":{"base-color":{"default":"#2099d8","value":"#2099d8","edited":true},"page-titlebar-backgroundColor":{"value":"#2099d8","edited":false},"page-backgroundColor":{"value":"#000000","edited":true},"page-sidebar-backgroundColor":{"value":"#000000","edited":true},"group-textColor":{"value":"#5db8e7","edited":false},"group-borderColor":{"value":"#2b2b2d","edited":true},"group-backgroundColor":{"value":"#2b2b2d","edited":true},"widget-textColor":{"value":"#ffffff","edited":true},"widget-backgroundColor":{"value":"#2099d8","edited":false},"widget-borderColor":{"value":"#2b2b2d","edited":true},"base-font":{"value":"-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif"}},"angularTheme":{"primary":"indigo","accents":"blue","warn":"red","background":"grey"}},"site":{"name":"My iot Dashboard","hideToolbar":"false","allowSwipe":"false","lockMenu":"false","allowTempTheme":"true","dateFormat":"DD/MM/YYYY","sizes":{"sx":48,"sy":48,"gx":6,"gy":6,"cx":6,"cy":6,"px":0,"py":0}}},{"id":"e318e60c.26e868","type":"ui_group","z":"","name":"Moisture Chart 2","tab":"6642d783.4c9c38","order":2,"disp":true,"width":"8","collapse":false},{"id":"630aa2ae.8c6cec","type":"ui_spacer","name":"spacer","group":"454c2947.1fa2c8","order":1,"width":1,"height":1},{"id":"6642d783.4c9c38","type":"ui_tab","z":"","name":"Moisture Details","icon":"dashboard","order":2,"disabled":false,"hidden":false},{"id":"b8708033.94d86","type":"ui_group","z":"","name":"Field Moisture Gauge","tab":"3a5681c6.69c0a6","order":3,"disp":true,"width":"6","collapse":false},{"id":"160544bc.95ef4b","type":"ui_group","z":"","name":"Field Moisture Level","tab":"3a5681c6.69c0a6","order":4,"disp":true,"width":"6","collapse":false},{"id":"973b4abf.8634a8","type":"ui_group","z":"","name":"Current Weather","tab":"3b35c1b2.64028e","order":4,"disp":true,"width":"6","collapse":false},{"id":"b5cb8ceb.ffc","type":"ui_group","z":"","name":"Hourly Weather Forecast","tab":"3b35c1b2.64028e","order":3,"disp":true,"width":"6","collapse":false},{"id":"c96008f2.e6b69","type":"ui_group","z":"","name":"Moisture Chart 1","tab":"6642d783.4c9c38","order":1,"disp":true,"width":"8","collapse":false},{"id":"3a5681c6.69c0a6","type":"ui_tab","z":"","name":"Pump Status ","icon":"dashboard","order":1,"disabled":false,"hidden":false},{"id":"bec8b727.033f","type":"ui_group","z":"","name":"Pump Status","tab":"3a5681c6.69c0a6","order":5,"disp":false,"width":"12","collapse":false},{"id":"3b35c1b2.64028e","type":"ui_tab","z":"","name":"Weather ","icon":"dashboard","order":3,"disabled":false,"hidden":false},{"id":"350b09af.e3ed46","type":"ui_group","z":"","name":"Moisture Sensor 1","tab":"3a5681c6.69c0a6","order":1,"disp":true,"width":"6","collapse":false},{"id":"9be2405.535364","type":"ui_group","z":"","name":"Moisture Sensor 2","tab":"3a5681c6.69c0a6","order":2,"disp":true,"width":"6","collapse":false},{"id":"a3dae5fe.27d948","type":"mqtt in","z":"2e2bc85.6e69438","name":"MQTT Receiver","topic":"SensorDataSaad","qos":"2","datatype":"auto","broker":"f4aa86c7.144588","x":142.74996948242188,"y":334.5000305175781,"wires":[["968f0139.ea5db","322ef2a1.623236"]]},{"id":"968f0139.ea5db","type":"json","z":"2e2bc85.6e69438","name":"","property":"payload","action":"","pretty":true,"x":318.7499694824219,"y":334.25001525878906,"wires":[["5be35248.b98b4c"]]},{"id":"43ae60ee.b38ee","type":"function","z":"2e2bc85.6e69438","name":"Get Moisture Reading 1","func":"\n//For Resistive Moisture Sensor\nmsg.payload = Number(msg.payload.D);\nmsg.payload =(msg.payload)*(100/1638);\nreturn msg;\n","outputs":1,"noerr":0,"x":242.37307739257812,"y":512.0951232910156,"wires":[["bb964cfb.c46db"]]},{"id":"6c7734c6.b4142c","type":"function","z":"2e2bc85.6e69438","name":"Pump on/off","func":"\n\nif (msg.payload < 25 )\n\n{\nmsg.payload = \"Moisture Low.So Pump is Turned ON\"\n}\nelse if (msg.payload >25 )\n{\n    msg.payload = \"Moisture Normal. Pump Turned OFF\"\n}\n\nelse {\n    return null;\n}\nreturn msg;\n","outputs":1,"noerr":0,"x":209.17143630981445,"y":984.7641334533691,"wires":[["8134b57a.9ea6f8","dc7df5c.1dcca08"]]},{"id":"8134b57a.9ea6f8","type":"rbe","z":"2e2bc85.6e69438","name":"Control","func":"rbe","gap":"","start":"","inout":"out","property":"payload","x":493.17156982421875,"y":982.9640502929688,"wires":[["73646a62.3c6c54"]]},{"id":"8ace368b.d24848","type":"ui_chart","z":"2e2bc85.6e69438","name":"MS2 Chart","group":"e318e60c.26e868","order":1,"width":"8","height":"5","label":"","chartType":"line","legend":"false","xformat":"auto","interpolate":"linear","nodata":"","dot":false,"ymin":"0","ymax":"100","removeOlder":"10","removeOlderPoints":"100","removeOlderUnit":"60","cutout":0,"useOneColor":false,"colors":["#1f75b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"outputs":1,"x":889.1517333984375,"y":572.380859375,"wires":[[]]},{"id":"8ccebab4.529508","type":"ui_gauge","z":"2e2bc85.6e69438","name":"MS Gauge","group":"b8708033.94d86","order":1,"width":"6","height":"5","gtype":"gage","title":"","label":"","format":"{{msg.payload.toFixed(0)}}%","min":0,"max":"100","colors":["#cf423f","#ff6800","#2099d8"],"seg1":"20","seg2":"40","x":718.9927978515625,"y":727.1427612304688,"wires":[]},{"id":"fdafb5f7.60c618","type":"ui_gauge","z":"2e2bc85.6e69438","name":"MS Wave","group":"160544bc.95ef4b","order":1,"width":"6","height":"5","gtype":"wave","title":"","label":"%","format":"{{value}}","min":0,"max":"100","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","x":717.6594848632812,"y":802.6149291992188,"wires":[]},{"id":"bb964cfb.c46db","type":"smooth","z":"2e2bc85.6e69438","name":"","property":"payload","action":"mean","count":"10","round":"0","mult":"single","x":458.373104095459,"y":512.0950918197632,"wires":[["2c0338ac.ab6d58"]]},{"id":"73646a62.3c6c54","type":"ui_toast","z":"2e2bc85.6e69438","position":"bottom right","displayTime":"5","highlight":"","outputs":0,"ok":"OK","cancel":"","topic":"iot Dashboard","name":"","x":731.5714416503906,"y":982.9641094207764,"wires":[]},{"id":"5cd8e61b.4eccf8","type":"function","z":"2e2bc85.6e69438","name":"Get Moisture Reading 2","func":"\nmsg.payload = Number(msg.payload.D);\nmsg.payload =100- ((msg.payload-650)/(1340-650)*100);\nreturn msg;\n\n/*For Resistive Moisture Sensor\nmsg.payload = Number(msg.payload.d.Data);\nmsg.payload =(msg.payload)*(100/4095);\nreturn msg;\n*/","outputs":1,"noerr":0,"x":255.93026733398438,"y":573.7237854003906,"wires":[["301f7b80.bcf064"]]},{"id":"301f7b80.bcf064","type":"smooth","z":"2e2bc85.6e69438","name":"","property":"payload","action":"mean","count":"10","round":"0","mult":"single","x":469.93023681640625,"y":573.7237854003906,"wires":[["c8865255.80e26"]]},{"id":"2c0338ac.ab6d58","type":"function","z":"2e2bc85.6e69438","name":"Moisture Sensor 1","func":"global.set(\"MoistureSensor1\" ,msg.payload);\nreturn msg;","outputs":1,"noerr":0,"x":664.2500610351562,"y":511.69281005859375,"wires":[["8682f0da.de5138","3b72e2dd.de18d6"]]},{"id":"c8865255.80e26","type":"function","z":"2e2bc85.6e69438","name":"Moisture Sensor 2","func":"\n\nglobal.set(\"MoistureSensor2\" ,msg.payload);\nreturn msg;","outputs":1,"noerr":0,"x":661.4856567382812,"y":573.5929565429688,"wires":[["8ace368b.d24848","17e74f8b.a59f9"]]},{"id":"5187d824.8b6f8","type":"link in","z":"2e2bc85.6e69438","name":"","links":["eaf880d9.935aa"],"x":82.80160522460938,"y":512.6381530761719,"wires":[["43ae60ee.b38ee"]]},{"id":"eaf880d9.935aa","type":"link out","z":"2e2bc85.6e69438","name":"Sensor1 Data","links":["5187d824.8b6f8"],"x":580.3928833007812,"y":292.21429443359375,"wires":[]},{"id":"27f6b92d.59c9fe","type":"link out","z":"2e2bc85.6e69438","name":"Senson2 Data","links":["86d45bd0.78aae8"],"x":577.5357055664062,"y":370.9285888671875,"wires":[]},{"id":"86d45bd0.78aae8","type":"link in","z":"2e2bc85.6e69438","name":"","links":["27f6b92d.59c9fe"],"x":81.87312316894531,"y":571.0381164550781,"wires":[["5cd8e61b.4eccf8"]]},{"id":"8682f0da.de5138","type":"ui_chart","z":"2e2bc85.6e69438","name":"MS1 Chart","group":"c96008f2.e6b69","order":2,"width":"8","height":"5","label":"","chartType":"line","legend":"false","xformat":"auto","interpolate":"linear","nodata":"","dot":false,"ymin":"0","ymax":"100","removeOlder":"1","removeOlderPoints":"100","removeOlderUnit":"60","cutout":0,"useOneColor":false,"colors":["#1f75b4","#aec7e8","#ff7f0e","#008000","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"outputs":1,"x":888.39453125,"y":511.36669921875,"wires":[[]]},{"id":"2bf932b9.b1547e","type":"inject","z":"2e2bc85.6e69438","name":"Clock","topic":"","payload":"","payloadType":"date","repeat":"1","crontab":"","once":true,"onceDelay":0.1,"x":154.62498474121094,"y":802.5,"wires":[["eb13304a.60257"]]},{"id":"eb13304a.60257","type":"function","z":"2e2bc85.6e69438","name":"Average of Both Moisture Sensor Data","func":"var test = global.get(\"MoistureSensor1\")+global.get(\"MoistureSensor2\");\nmsg.payload = test/2;\nreturn msg;","outputs":1,"noerr":0,"x":429.875,"y":804,"wires":[["8ccebab4.529508","fdafb5f7.60c618","6c7734c6.b4142c"]]},{"id":"5be35248.b98b4c","type":"switch","z":"2e2bc85.6e69438","name":"Switch","property":"payload.Arafat","propertyType":"msg","rules":[{"t":"eq","v":"M1","vt":"str"},{"t":"eq","v":"M2","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":474.67852783203125,"y":334.9000244140625,"wires":[["eaf880d9.935aa"],["27f6b92d.59c9fe"]]},{"id":"b538f080.c1807","type":"comment","z":"2e2bc85.6e69438","name":"Global Variable","info":"Global Variable","x":670.3999938964844,"y":459.8499755859375,"wires":[]},{"id":"dc7df5c.1dcca08","type":"link out","z":"2e2bc85.6e69438","name":"","links":["7e9bda60.11e67c","13390a8a.b6dd15","d970573c.59f8e"],"x":450,"y":1051.6499633789062,"wires":[]},{"id":"3b72e2dd.de18d6","type":"ui_gauge","z":"2e2bc85.6e69438","name":"Moisture Sensor1","group":"350b09af.e3ed46","order":1,"width":"6","height":"5","gtype":"gage","title":"","label":"","format":"{{msg.payload.toFixed(0)}}%","min":0,"max":"100","colors":["#e10000","#e6e600","#008040"],"seg1":"20","seg2":"40","x":910.7779541015625,"y":461.27777099609375,"wires":[]},{"id":"17e74f8b.a59f9","type":"ui_gauge","z":"2e2bc85.6e69438","name":"Moisture Sensor2","group":"9be2405.535364","order":3,"width":"6","height":"5","gtype":"gage","title":"","label":"","format":"{{msg.payload.toFixed(0)}}%","min":0,"max":"100","colors":["#e10000","#e6e600","#008040"],"seg1":"20","seg2":"40","x":908.222412109375,"y":637.0556640625,"wires":[]},{"id":"de968a88.91464","type":"openweathermap in","z":"8e39dbe1.c473b","name":"Current Weather","wtype":"current","lon":"-0.3569340502747274","lat":"53.774493500000005","city":"","country":"","language":"en","x":184,"y":194,"wires":[["6641c5be.0c5324"]]},{"id":"80ac48f0.d84b48","type":"ui_template","z":"8e39dbe1.c473b","group":"973b4abf.8634a8","name":"icon","order":1,"width":"3","height":"2","format":"<div style=\"display: flex;height: 100%;justify-content: center;align-items: center;\">\n<i class=\"fa-4x wi wi-owm-{{msg.payload}}\"></i>\n</div>","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":901.0000610351562,"y":103.00000095367432,"wires":[[]]},{"id":"6641c5be.0c5324","type":"function","z":"8e39dbe1.c473b","name":"Splitter","func":"var icon = { payload:msg.payload.icon };\nvar detail = { payload:msg.payload.detail};\nvar tempc = { payload:msg.payload.tempc};\nvar humidity = { payload:msg.payload.humidity};\nvar windspeed = { payload:msg.payload.windspeed};\n\n\nreturn [ icon, detail, tempc, humidity, windspeed];","outputs":5,"noerr":0,"x":387.0000762939453,"y":195,"wires":[["80ac48f0.d84b48"],["7a6bb02f.b161e8"],["f27ce467.24658"],["1fe4bf05.222891"],["509e300.1c8e4d"]]},{"id":"7a6bb02f.b161e8","type":"ui_text","z":"8e39dbe1.c473b","group":"973b4abf.8634a8","order":2,"width":"3","height":"1","name":"Detail Weather","label":"","format":"{{msg.payload}}","layout":"row-right","x":930.0000610351562,"y":146.00000095367432,"wires":[]},{"id":"f27ce467.24658","type":"ui_text","z":"8e39dbe1.c473b","group":"b5cb8ceb.ffc","order":3,"width":"6","height":"1","name":"Temperature","label":"Temperature","format":"{{msg.payload}} °C","layout":"row-spread","x":919.9000091552734,"y":194.00000095367432,"wires":[]},{"id":"1fe4bf05.222891","type":"ui_text","z":"8e39dbe1.c473b","group":"973b4abf.8634a8","order":4,"width":"6","height":"1","name":"Humidity","label":"Humidity","format":"{{msg.payload}} %","layout":"row-spread","x":907.9000091552734,"y":236.00000286102295,"wires":[]},{"id":"769fcdf1.d304dc","type":"openweathermap in","z":"8e39dbe1.c473b","name":"Weather Forecast","wtype":"forecast","lon":"-0.3569340502747274","lat":"53.774493500000005","city":"","country":"","language":"en","x":193.9000129699707,"y":405.8000030517578,"wires":[["e4046d0b.d09798"]]},{"id":"e4046d0b.d09798","type":"function","z":"8e39dbe1.c473b","name":"Splitter","func":"var msg1 = { payload:msg.payload[0].weather[0].icon };\nvar msg2 = { payload:msg.payload[0].weather[0].description};\nvar msg3 = { payload:msg.payload[0].main.temp};\nvar msg4 = { payload:msg.payload[0].main.humidity};\nvar msg5 = { payload:msg.payload[0].wind.speed};\n\n\nreturn [ msg1, msg2, msg3, msg4, msg5];","outputs":5,"noerr":0,"x":384.0000991821289,"y":405.8000030517578,"wires":[["55d3db3a.334114"],["315f73ba.6899f4"],["6851733b.e50ce4"],["d04fc99.da85fb8"],["501627eb.588418"]]},{"id":"6851733b.e50ce4","type":"ui_text","z":"8e39dbe1.c473b","group":"973b4abf.8634a8","order":3,"width":"6","height":"1","name":"Temperature","label":"Temperature","format":"{{msg.payload}} °C","layout":"row-spread","x":919.7999649047852,"y":453.80000591278076,"wires":[]},{"id":"d04fc99.da85fb8","type":"ui_text","z":"8e39dbe1.c473b","group":"b5cb8ceb.ffc","order":4,"width":"6","height":"1","name":"Humidity","label":"Humidity","format":"{{msg.payload}} %","layout":"row-spread","x":911.7999649047852,"y":501.80000591278076,"wires":[]},{"id":"315f73ba.6899f4","type":"ui_text","z":"8e39dbe1.c473b","group":"b5cb8ceb.ffc","order":2,"width":"3","height":"1","name":"Detail Weather","label":"","format":"{{msg.payload}} ","layout":"row-right","x":931.9000091552734,"y":403.80000400543213,"wires":[]},{"id":"55d3db3a.334114","type":"ui_template","z":"8e39dbe1.c473b","group":"b5cb8ceb.ffc","name":"icon","order":1,"width":"3","height":"2","format":"<div style=\"display: flex;height: 100%;justify-content: center;align-items: center;\">\n<i class=\"fa-4x wi wi-owm-{{msg.payload}}\"></i>\n</div>","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":902.9000091552734,"y":345.80000352859497,"wires":[[]]},{"id":"509e300.1c8e4d","type":"ui_text","z":"8e39dbe1.c473b","group":"973b4abf.8634a8","order":4,"width":"6","height":"1","name":"Wind Speed","label":"Wind Speed","format":"{{msg.payload}} m/s","layout":"row-spread","x":919.1000099182129,"y":276.99999237060547,"wires":[]},{"id":"501627eb.588418","type":"ui_text","z":"8e39dbe1.c473b","group":"b5cb8ceb.ffc","order":4,"width":"6","height":"1","name":"Wind Speed","label":"Wind Speed","format":"{{msg.payload}} m/s","layout":"row-spread","x":922.1000099182129,"y":548.9999923706055,"wires":[]},{"id":"322ef2a1.623236","type":"debug","z":"2e2bc85.6e69438","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":424.49998474121094,"y":204.8000030517578,"wires":[]},{"id":"af036b41.96e118","type":"mqtt in","z":"a74037fd.22229","name":"Status signal","topic":"maaislamPumpStatus","qos":"2","datatype":"auto","broker":"f4aa86c7.144588","x":337.344482421875,"y":344.7555236816406,"wires":[["11ece5e.107b49a"]]},{"id":"11ece5e.107b49a","type":"json","z":"a74037fd.22229","name":"","property":"payload","action":"","pretty":false,"x":609.344482421875,"y":345.55552673339844,"wires":[["ae7d6592.b3f43"]]},{"id":"ae7d6592.b3f43","type":"function","z":"a74037fd.22229","name":"Converter","func":"\nif ( msg.payload.d.Data == 1){\n    \n    msg.payload = \"Pump ON\"; \n}\nelse if (msg.payload.d.Data === 0)\n{\n   msg.payload = \"Pump OFF\";\n}\nelse {\n    return null;\n}\nreturn msg;","outputs":1,"noerr":0,"x":330.67779541015625,"y":477.08888244628906,"wires":[["66710d7d.184004","a6918717.de2cf8"]],"info":"This function takes the Data item from json \nand converts it to boolean form."},{"id":"be20885c.1eb95","type":"mqtt out","z":"a74037fd.22229","name":"Control Signal","topic":"maaislamPumpControl","qos":"2","retain":"","broker":"f4aa86c7.144588","x":727.4222412109375,"y":223.1110076904297,"wires":[]},{"id":"d970573c.59f8e","type":"link in","z":"a74037fd.22229","name":"","links":["dc7df5c.1dcca08"],"x":253.755615234375,"y":220.02207946777344,"wires":[["4ee1f73a.5e2f68"]]},{"id":"4ee1f73a.5e2f68","type":"change","z":"a74037fd.22229","name":"","rules":[{"t":"change","p":"payload","pt":"msg","from":"Moisture Low.So Pump is Turned ON","fromt":"str","to":"1","tot":"num"},{"t":"change","p":"payload","pt":"msg","from":"Moisture Normal. Pump Turned OFF","fromt":"str","to":"0","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":383.12225341796875,"y":221.31101989746094,"wires":[["be20885c.1eb95"]]},{"id":"1a73ea89.b1e675","type":"ui_text","z":"a74037fd.22229","group":"bec8b727.033f","order":1,"width":"5","height":"2","name":"cog","label":"","format":"<font color={{msg.color}} ><i class=\"{{msg.class}}\"style=\"font-size:24px;\"></i></font>","layout":"row-right","x":781.9000244140625,"y":513.2000122070312,"wires":[]},{"id":"66710d7d.184004","type":"function","z":"a74037fd.22229","name":"Cog Icon","func":"\nmsg.class = \n(msg.payload == \"Pump ON\")?\"fa fa-cog fa-spin fa-5x fa-fw\":\"fa fa-cog fa-5x fa-f\";\n//Shows a staic or spinning cof icon based on the message\n\n\n\nmsg.color = \n(msg.payload == \"Pump ON\")?\"lime\":\"red\";// Changes color of the cog based on the message\n\nreturn msg;\n","outputs":1,"noerr":0,"x":589.2000122070312,"y":510.2000274658203,"wires":[["1a73ea89.b1e675"]]},{"id":"a6918717.de2cf8","type":"function","z":"a74037fd.22229","name":"Status Text","func":"\nswitch (msg.payload) {\n\ncase \"Pump ON\" : // if incoming message is \"Pump ON\"\n    msg.color = \"lime\";// change message text color.\n    msg.payload = \"Pump ON\";// show message\n    msg.size = \"8\";// increase message font size.\n    break;\n    \ncase \"Pump OFF\" : // if incoming message is \"Pump OFF\"\n    msg.color = \"red\"; // change message text color.\n    msg.payload = \"Pump OFF\"; // show message.\n    msg.size = \"8\"; // increase message font size.\n    break;\n    \n}\n\nreturn msg;","outputs":1,"noerr":0,"x":600.2000122070312,"y":456.2000274658203,"wires":[["a6afa763.bfc078"]]},{"id":"a6afa763.bfc078","type":"ui_text","z":"a74037fd.22229","group":"bec8b727.033f","order":3,"width":"6","height":"2","name":"text","label":"","format":"<font color= {{msg.color}}  size= {{msg.size}}> {{msg.payload}} </font>","layout":"row-left","x":784.2000122070312,"y":457.2000274658203,"wires":[]}]

Cloud_Gateway

C/C++
/*
 *
 *  This example demonstrates usage of the AIR430BoostETSI library which uses
 *  the 430Boost-CC110L AIR Module BoosterPack created by Anaren Microwave, Inc.
 *  and available through the TI eStore, for the European Union.
 */





#include <AIR430BoostFCC.h>
#include <SPI.h>
#include <WiFi.h>
#include <PubSubClient.h>



// -----------------------------------------------------------------------------
/**
 *  Global data
 */

unsigned char rxData[60];           // Data to read from radio RX FIFO (60 bytes MAX.)
char ssid[] = "maaislam";          // LenovoWIFI your network name also called SSID
char password[] = "123asdfgh";       // your network password
char server[] = "broker.hivemq.com";  // MQTTServer to use
WiFiClient wifiClient;              // Connecting to MQTT broker via Wi-Fi
PubSubClient client(server, 1883, callback, wifiClient);  // Initialize MQTT client

// -----------------------------------------------------------------------------
// RF packet received!

void printRxData()
{
  // If RF data received, print diagnostic info to Serial Monitor & Publish over MQTT
  Serial.print("RX (DATA, RSSI, LQI, CRCBIT): ");
  Serial.print("(");
  Serial.print((char*)rxData);
  Serial.print(", ");
  Serial.print(Radio.getRssi());
  Serial.print(", ");
  Serial.print(Radio.getLqi());
  Serial.print(", ");
  Serial.print(Radio.getCrcBit());
  Serial.println(")");

  // Publish latest RF payload to the cloud via MQTT, Blink Yellow LED if successful
  if(client.publish("SensorDataSaad",(char*)rxData)) {
    digitalWrite(YELLOW_LED, HIGH);
    Serial.println("MQTT Publish success!");
    digitalWrite(YELLOW_LED, LOW);
  } else {
    Serial.println("MQTT Publish failed!");
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
// Not used
}
//
// -----------------------------------------------------------------------------
// Main

void setup()
{
  //Setup LED for example demonstration purposes.
  pinMode(RED_LED, OUTPUT);       // RED LED Notifier for subGHz RF Rx
  digitalWrite(RED_LED, LOW);
  pinMode(GREEN_LED, OUTPUT);     // GREEN LED Notifier for Wi-Fi connected
  digitalWrite(GREEN_LED, LOW);
  pinMode(YELLOW_LED, OUTPUT);    // YELLOW LED Notifier for MQTT Pub successful
  digitalWrite(YELLOW_LED, LOW);
  pinMode(PUSH1, INPUT);          // Configure PUSH1. Used to decide how we will connect to Wi-Fi

  // Setup serial for debug printing.
  Serial.begin(115200);

    Serial.print("Attempting to connect to Network named: ");
    // print the network name (SSID);
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    WiFi.begin(ssid, password);
    while ( WiFi.status() != WL_CONNECTED) {
      // print dots while we wait to connect
      Serial.print(".");
      delay(300);}

  // Connected to Wi-Fi!
  Serial.println("\nYou're connected to the network");
  Serial.println("Waiting for an ip address");

  // Wait for IP Address
  while (WiFi.localIP() == INADDR_NONE) {
    // print dots while we wait for an ip addresss
    Serial.print(".");
    delay(300);
  }
  Serial.println("\nIP Address obtained");

  // We are connected and have an IP address. Print the WiFi status.
  printWifiStatus();

  // ATTEMPT TO INITIALIZE CC110L SUBGHz RADIO
  // The radio library uses the SPI library internally, this call initializes
  // SPI/CSn and GDO0 lines. Also setup initial address, channel, and TX power.
  Radio.begin(0x01, CHANNEL_1, POWER_MAX);
}

void loop()
{
  // Reconnect to MQTT Broker if the connection was lost
  if (!client.connected()) {
    Serial.println("Disconnected. Reconnecting to MQTT Broker");
    client.connect("123asdfg_gateway1");
    Serial.println("Connected to MQTT Broker!");
  }

  // Turn on the receiver and listen for incoming data. Timeout after 1 seconds.
  // The receiverOn() method returns the number of bytes copied to rxData.
  if (Radio.receiverOn(rxData, 60, 1000) > 0)
  {
    /**
     *  Data has been received and has been copied to the rxData buffer provided
     *  to the receiverOn() method. At this point, rxData is available. See
     *  printRxData() for more information.
     */
    digitalWrite(RED_LED, HIGH);
    printRxData();                  // RX debug information
    digitalWrite(RED_LED, LOW);
  }
  
  // Ping MQTT broker to maintain connection
  client.poll();
}

void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:

  digitalWrite(GREEN_LED, HIGH);  // Connected to WiFi LED
}

Filter

C/C++
#pragma once

/*
* Implements a simple linear recursive exponential filter.
* See: http://www.statistics.com/glossary&term_id=756 */
template<class T> class ExponentialFilter
{
  // Weight for new values, as a percentage ([0..100])
  T m_WeightNew;

  // Current filtered value.
  T m_Current;

public:
  ExponentialFilter(T WeightNew, T Initial)
    : m_WeightNew(WeightNew), m_Current(Initial)
  { }

  void Filter(T New)
  {
    m_Current = (100 * m_WeightNew * New + (100 - m_WeightNew) * m_Current + 50)/100;
  }

  void SetWeight(T NewWeight)
  {
    m_WeightNew = NewWeight;
  }

  T GetWeight() const { return m_WeightNew; }

  T Current() const { return (m_Current + 50)/100; }

  void SetCurrent(T NewValue)
  {
    m_Current = NewValue*100;
  }
};

// Specialization for floating point math.
template<> class ExponentialFilter<float>
{
  float m_fWeightNew;
  float m_fCurrent;

public:
  ExponentialFilter(float fWeightNew, float fInitial)
    : m_fWeightNew(fWeightNew/100.0), m_fCurrent(fInitial)
  { }


  void Filter(float fNew)
  {
    m_fCurrent = m_fWeightNew * fNew + (1.0 - m_fWeightNew) * m_fCurrent;
  }

  void SetWeight(float NewWeight)
  {
    m_fWeightNew = NewWeight/100.0;
  }

  float GetWeight() const { return m_fWeightNew*100.0; }

  float Current() const { return m_fCurrent; }

  void SetCurrent(float fNewValue)
  {
    m_fCurrent = fNewValue;
  }
};

LCD Library(header file)

C/C++
LCD_Launchpad header file
/* --COPYRIGHT--,BSD
 * Copyright (c) 2015, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * --/COPYRIGHT--*/
/*******************************************************************************
 *
 * LCD_Launchpad.h
 *
 * Hardware abstraction layer for the FH-1138P Segmented LCD
 * on MSP-EXP430FR6989 and MSP-EXP430FR4133
 *
 * February 2015
 * E. Chen
 *
 * June 2015 StefanSch: Adopted for Energia
 *
 ******************************************************************************/

#ifndef LCD_LAUNCHPAD_H_
#define LCD_LAUNCHPAD_H_

#include "Energia.h"

enum LCD_ICONS {
  LCD_SEG_MARK,
  LCD_SEG_R,
  LCD_SEG_HEART,
  LCD_SEG_CLOCK,
  LCD_SEG_DOT3,
  LCD_SEG_RADIO,
  LCD_SEG_DOT2,
  LCD_SEG_COLON2,
  LCD_SEG_RX,
  LCD_SEG_TX,
  LCD_SEG_DOT1,
  LCD_SEG_MINUS1,
  LCD_SEG_BAT_POL,
  LCD_SEG_BAT1,
  LCD_SEG_BAT3,
  LCD_SEG_BAT5,
  LCD_SEG_DOT5,
  LCD_SEG_DEG5,
  LCD_SEG_BAT_ENDS,
  LCD_SEG_BAT0,
  LCD_SEG_BAT2,
  LCD_SEG_BAT4,
  LCD_SEG_DOT4,
  LCD_SEG_COLON4,
};

class LCD_LAUNCHPAD : public Print {
public:
    LCD_LAUNCHPAD();
    void init();

    void displayText(String s);
    void displayText(String s, char pos);
    void displayText(char* s, char pos);
    void displayScrollText(char* s, unsigned int wait);
    void showChar(char, int);
    void showSymbol(char symbol, int status);
    void clear(void);

    virtual size_t write(uint8_t c);
    //virtual size_t write(const uint8_t *buffer, size_t size);
    using Print::write; // pull in write(str) and write(buf, size) from Print
};

#endif /* LCD_LAUNCHPAD_H_ */

Credits

Mohd Islam

Mohd Islam

1 project • 3 followers
Thanks to Adrian Fernandez.

Comments