Monthly Archives: February 2016

DS-1302 RTC Clock Module for Arduino

DS-1302 from Maxim (data sheet download) is a cheap RTC chip. Below are some of the salient features.

  1. Real-Time Clock Counts Seconds,Minutes, Hours, Date of the Month, Month, Day of the Week, and Year with Leap-Year Compensation Valid Up to 2100
  2. Simple 3-Wire Interface
  3. 2.0V to 5.5V Full Operation
  4. TTL-Compatible (VCC = 5V)
  5. 31 x 8 Battery-Backed General-Purpose RAM
There are breakout boards available on ebay, which will be handy to build RTC based projects with Arduino. Look for China based sellers for a cheap price.
DS-1302 RTC 2 DS-1302 RTC 1DS-1302 RTC 3DS-1302 RTC 4
Though there are various modules available but the above two types I found to be working properly.
The below board didn't work at all. Notice the PCB trace which indicates the poor quality.Unfortunately there was no way to know this before delivery.

DS-1302 RTC - Bad  DS-1302 RTC - Bad 2
For those modules which has two power pins (VCC1 and VCC2), power to be connected to VCC2, VCC1 is connected to battery
The below code can be used to used to write and read time from the chip. Credit for the DS1302 library used here goes to Matt Sparks.  The library can be downloaded from Github and also from here (in case it goes off from Github).
Below is a code snippet (based on Matt Spark’s work) for setting time and reading it back easily. Please note for writing to the chip VCC2 needs to be given power (I used 5v).
    //http://datasheets.maximintegrated.com/en/ds/DS1302.pdf

    #include <DS1302.h>
    //#include <SoftwareSerial.h>

    //SoftwareSerial mySerial(2, 3); // RX, TX

    namespace {

      // Set the appropriate digital I/O pin connections.
      
      const int kCePin   = 8;  // Chip Enable (Some calls it Reset)
      const int kIoPin   = 7;  // Input/Output
      const int kSclkPin = 6;  // Serial Clock
      
      // Create a DS1302 object.
      DS1302 rtc(kCePin, kIoPin, kSclkPin);
      
      String dayAsString(const Time::Day day) {
        switch (day) {
          case Time::kSunday: return "Sunday";
          case Time::kMonday: return "Monday";
          case Time::kTuesday: return "Tuesday";
          case Time::kWednesday: return "Wednesday";
          case Time::kThursday: return "Thursday";
          case Time::kFriday: return "Friday";
          case Time::kSaturday: return "Saturday";
        }
        return "(unknown day)";
      }
      
      void printTime() {
        // Get the current time and date from the chip.
        Time t = rtc.time();
      
        // Name the day of the week.
        const String day = dayAsString(t.day);
      
        // Format the time and date and insert into the temporary buffer.
        char buf[50];
        snprintf(buf, sizeof(buf), "%s %04d-%02d-%02d %02d:%02d:%02d",
                 day.c_str(),
                 t.yr, t.mon, t.date,
                 t.hr, t.min, t.sec);
      
        // Print the formatted string to serial so we can see the time.
        Serial.println(buf);
        //mySerial.println(buf);
      }

    }  // end of namespace

    void setup() {
      Serial.begin(9600);
      //mySerial.begin(38400);
      // Initialize a new chip by turning off write protection and clearing the clock halt flag.
      rtc.writeProtect(false); //should be set to true after writing to prevent accidental writes
      rtc.halt(false);

      // Year month day hour min sec. DOW
      Time t(2016, 2, 28, 19, 9, 30, Time::kSunday);

      // Set the time and date on the chip.
      rtc.time(t);  //after writing once, comment/remove this code to prevent unnecessary/wrong re-writing of the time
    }

    // Loop and print the time every 5 seconds.
    void loop() {
      printTime(); //prints the date and time
      
      delay(5000);
    }

Arduino – Communicate With Server – Part 3 – Web Based Panel

This is the code for the web based panel (web based UI) that will display the data received from arduino or can send some command to the Arduino

All communications are done through a server (web server)

The frontend code

<?php
date_default_timezone_set("Asia/Kolkata");
$conn = mysql_connect("localhost","root","xxxxxxxxxx");
if(!$conn)
{
    echo "Error: failed to connect DB";
    die();
}

if(!mysql_select_db("xxxxxxxx",$conn))
{
    echo "Error: failed to connect DB";
    die();
}
$jsonArray1 = array();
$jsonArray2 = array();
$i=0;

$result = mysql_query("select * from weather");
while($rows = mysql_fetch_array($result))
{
    $jsonArray1[$i] = array(date("Y,m,d,H,i",$rows['time']), floatval($rows['temperature']));
    $jsonArray2[$i++] = array(date("Y,m,d,H,i",$rows['time']), floatval($rows['paM']));
}
?>
<html>
  <head>
  <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
  <script type="text/javascript">
      var chart, chart2;
      window.onload = function () {
        chart = new CanvasJS.Chart("chartContainer",
        {
          title:{
          text: "Temperature"
          },
          axisY:{
            minimum: 0,
            maximum: 50      
          },
           data: [
          {
            type: "line",
    
            dataPoints: [
            <?php
                for($j=0;$j<$i;$j++)
                {
           ?>
                       { x: new Date(<?php echo $jsonArray1[$j][0] ?>), y: <?php echo $jsonArray1[$j][1] ?> } <?php echo $j<$i-1?"," :"" ?>
           <?php         
                }
            ?>            
            ]
          }
          ]
        });
    
        chart.render();
        
        
        chart2 = new CanvasJS.Chart("chartContainer2",
        {
          title:{
          text: "paM"
          },
          axisY:{
            minimum: 1000,
            maximum: 1040      
          },
           data: [
          {
            type: "line",
    
            dataPoints: [
            <?php
                for($j=0;$j<$i;$j++)
                {
           ?>
                       { x: new Date(<?php echo $jsonArray2[$j][0] ?>), y: <?php echo $jsonArray2[$j][1] ?> } <?php echo $j<$i-1?"," :"" ?>
           <?php         
                }
            ?>            
            ]
          }
          ]
        });
    
        chart2.render();
      }
      
    function updateTemp() 
    {
        var str = JSON.parse(updateData("t"));
        var date = str[1].split(",");
        chart.options.data[0].dataPoints.push({x : new Date(date[0],date[1],date[2],date[3],date[4]),  y : parseFloat(str[0]) });
          
        chart.render();         
    };
    
    function updatePressure() 
    {
          var str = JSON.parse(updateData("p"));
          var date = str[1].split(",");
        chart2.options.data[0].dataPoints.push({ x : new Date(date[0],date[1],date[2],date[3],date[4]), y : parseFloat(str[0]) });
        chart2.render();
    };
    
    function updateData(type)
    {
        var xmlhttp = new XMLHttpRequest();
        xmlhttp.open("GET", "dataPlotter.php?q=" + type, false);
        xmlhttp.send();
        return xmlhttp.responseText;
    }
    
    setInterval("updateTemp()",360000);
    setInterval("updatePressure()",480000);
    
  </script>
  </head>

  <body>
<?php
$result = mysql_query("select * from led_status");
$rows = mysql_fetch_array($result);
?>  
      LED 1 <input type="checkbox" value="<?php echo $rows['led_1']==1 ? 1 : 0 ?>" <?php echo $rows['led_1']==1 ? "checked="checked"" : "" ?> id="led_1" name="led_1" onclick="changeLEd('led_1')" />
      LED 2 <input type="checkbox" value="<?php echo $rows['led_2']==1 ? 1 : 0 ?>" <?php echo $rows['led_2']==1 ? "checked="checked"" : "" ?> id="led_2" name="led_2" onclick="changeLEd('led_2')" />
    <!--Div that will hold the column chart-->
    <div id="chartContainer" style="height: 300px; width: 100%;"></div>
    
    <div id="chartContainer2" style="height: 300px; width: 100%;"></div>
    
    <script src="canvasjs.min.js"></script>
    <script src="jquery.canvasjs.min.js"></script>
    
    <script type="text/javascript">
        function changeLEd(whichLed)
        {
            var state;
            
            if(document.getElementById(whichLed).checked == true)
            {
                state = 1;
            }
            else
            {
                state = 0;
            }
            
            var xmlhttp = new XMLHttpRequest();
            xmlhttp.open("GET", "change-led.php?which="+whichLed+"&state="+state, false);
            xmlhttp.send();
            return xmlhttp.responseText;
        }
    </script>
  </body>
</html>

The backend codes

dataplotter.php

<?php
date_default_timezone_set("Asia/Kolkata");
$conn = mysql_connect("localhost","root","xxxxxxxxxx");
if(!$conn)
{
    echo "Error: failed to connect DB";
    die();
}

if(!mysql_select_db("xxxxxxxx",$conn))
{
    echo "Error: failed to connect DB";
    die();
}
$jsonArray = array();
$i=0;

if(isset($_GET['q']) && strlen(strip_tags($_GET['q'])))
{
    $type = strip_tags($_GET['q']);
}
else
{
    $type = "t";
}

if($type == "t")
{
    $type = "temperature";
}
else
    if($type == "p")
    {
        $type = "paM";
    }

$result = mysql_query("select ".$type.",time from weather order by time desc limit 0,1");
$rows = mysql_fetch_array($result);

header('Content-Type: application/json');
echo json_encode(array($rows[$type],date("Y,m,d,H,i",$rows['time'])));
?>

change-led.php

<?php
$conn = mysql_connect("localhost","root","xxxxxxxxxx");
if(!$conn)
{
    echo "Error: failed to connect DB";
    die();
}

if(!mysql_select_db("xxxxxxx",$conn))
{
    echo "Error: failed to connect DB";
    die();
}

$whichLed = strip_tags($_GET['which']);
$state = strip_tags($_GET['state']);
mysql_query("update led_status set ".$whichLed." = ".intval($state));
?>

Arduino – Communicate With Server – Part 2 – Server Code for Saving Data

This article shows the server side code for a server which is gathering or sending data by polling method to an Arduino device.

This method or code is putting less load on the server (compared to socket) but data transmission is slower than socket.

<?php
date_default_timezone_set("Asia/Kolkata");
$conn = mysql_connect("localhost","root","**********");
if(!$conn)
{
    echo "Error: failed to connect DB Server";
    die();
}

if(!mysql_select_db("database_name",$conn))
{
    echo "Error: failed to connect DB";
    die();
}
$action = intval(strip_tags($_GET['action']));

if($action == 1)
{
    $temp = floatval(strip_tags($_GET['temp']));
    $paH = floatval(strip_tags($_GET['paH']));
    $paM = floatval(strip_tags($_GET['paM']));
    
    mysql_query("insert into weather (temperature, paH, paM, time) values(".$temp.",".$paH.",".$paM.",".time().")");
    //mysql_query("update led_status set led_1 = ".$led_1.", led_2 = ".$led_2);
    
    echo "success";
}
else
    if($action == 2)
    {
        $output = "";
        $result = mysql_query("select * from led_status");
        $rows = mysql_fetch_array($result);
        if($rows['led_1'] == 1)
        {
           $output = "led_1=1|";    
        }
        else
        {
           $output = "led_1=0|";    
        }
        
        if($rows['led_2'] == 1)
        {
           $output .= "led_2=1";    
        }
        else
        {
           $output .= "led_2=0";    
        }
        echo $output;
    }
    mysql_close($conn);
?>

 

The else part ( if($action == 2) ) output from the above will be

HTTP/1.1 200 OK
Date: Sun, 14 Feb 2016 20:33:16 GMT
Server: Apache/2.4.7 (Ubuntu)
X-Powered-By: PHP/5.5.9-1ubuntu4.14
Content-Length: 15
Connection: close
Content-Type: text/html

led_1=0|led_2=1

Arduino – Communicate With Server – Part 1 – Arduino code

The below code send some data (temperature and pressure here) to a server and reads back some data from server. The send part works every 5 minutes and the read part works every 5 seconds. This code works by polling method.

All delays might have room for optimization

#include <SFE_BMP180.h> //from sparkfun 
#include <Wire.h>
#include <SoftwareSerial.h>

#define _SS_MAX_RX_BUFF 512 // RX buffer size //Default is 64

SoftwareSerial esp8266(2,3);

String inputBuffer = "";
boolean stringComplete = false;
int inputBufferIndex;

int led1Pin = 9;
int led2Pin = 10;

byte led1Status, led2Status;

String data1 = ""; 
String data2 = "";
String data3 = "";
String data4 = "";
String data5 = "";

unsigned long startTimeDataCapture = 0;
unsigned long lastDataSent = 0;

SFE_BMP180 pressure;

char status;
double T,P,temp,paH,paM;


void setup() {
  // put your setup code here, to run once:
  
  inputBuffer.reserve(1024); //to be optimized
  
  pinMode(led1Pin, OUTPUT);
  pinMode(led2Pin, OUTPUT);
  
  pressure.begin();
  
  
  //Serial.begin(19200);

  esp8266.begin(9600);
  esp8266.println("AT");  delay(100);
  esp8266.println("AT+UART_CUR=4800,8,1,0,0"); //set the Baud rate 
  esp8266.flush(); delay(100);
  while(esp8266.available())
  {
      //Serial.write(esp8266.read());
      esp8266.read();  //clear the buffer
      delay(80);
  }
  esp8266.end();

  esp8266.begin(4800);
  esp8266.println("AT"); delay(100);
  
  esp8266.println("AT+CIPMUX=1"); delay(100);
  esp8266.println("AT+CWMODE=1"); delay(100); 
  esp8266.println("AT+CWJAP="TP-LINK_POCKET_3020_304764","password""); esp8266.flush();  delay(1000);  
  
  while(esp8266.available())
  {
      //Serial.write(esp8266.read());
      esp8266.read(); //clear the buffer
      delay(80);
  }
    
  delay(5000);
}


void loop() {

  while(esp8266.available())
  {
      //Serial.write(esp8266.read());
      esp8266.read();
      delay(10);
  }

  inputBuffer = "";
  stringComplete = false;
  
  /***** Read the LED status for sending to server  -- will be implemented later */
  if(digitalRead(led1Pin) == HIGH)
  {
    led1Status = 1;
  }
  else
  {
    led1Status = 0;
  }

  if(digitalRead(led2Pin) == HIGH)
  {
    led2Status = 1;
  }
  else
  {
    led2Status = 0;
  }
  
  status = pressure.startTemperature();
  if (status != 0)
  {
    // Wait for the measurement to complete:
    delay(status);

    // Retrieve the completed temperature measurement:
    // Note that the measurement is stored in the variable T.
    // Function returns 1 if successful, 0 if failure.

    status = pressure.getTemperature(T);
    if (status != 0)
    {
      temp = T;

      
      // Start a pressure measurement
      status = pressure.startPressure(3);
      if (status != 0)
      {
        // Wait for the measurement to complete:
        delay(status);


        // Note also that the function requires the previous temperature measurement (T).
        // (If temperature is stable, you can do one temperature measurement for a number of pressure measurements.)
        // Function returns 1 if successful, 0 if failure.

        status = pressure.getPressure(P,T);
        if (status != 0)
        {
          paM = P;
          paH = P*0.0295333727;
        }
        else
        {
          paM = -1;
          paH = -1;
        }
      }
      else
      {
          paM = -1;
          paH = -1;
      }
    }
    else
    {
      temp = -1;
    }
  }
  else
  {
    temp = -1;
  }

   
   //send the data to server
  
  if(millis() - lastDataSent > 300000) //send data every 5 minutes 
  {
      lastDataSent = millis();
      data1 = "GET /webservice.php?action=1&temp="+String(temp)+"&paM="+String(paM)+"&paH="+String(paH)+" HTTP/1.1";
  }
  else
  {
      data1 = "GET /webservice.php?action=2 HTTP/1.1";
  }
  //Serial.println(data1);
  data2 = "Host: xxx.xxx.xxx.xxx";
  data3 = "User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0";
  data4 = "Accept: text/html";
  data5 = "Connection: close";
  //Serial.println(data1.length()+data2.length()+data3.length()+data4.length()+data5.length());
  
  esp8266.println("AT+CIPSTART=4,"TCP","xxx.xxx.xxx.xxx",80");  delay(1000); 
   while(esp8266.available())
  {
      //Serial.write(esp8266.read());
      esp8266.read();
      delay(10);
  }
  esp8266.println("AT+CIPSEND=4,"+String(data1.length()+data2.length()+data3.length()+data4.length()+data5.length()+12)); // the 12 here is related to the data being sent below. Each dataline is sent using println (required to sent) which adds a \r\n after every line. \r and \n makes 2 chars. So for every data sent using println 2 count is increased in the total data length paramter of AT+CIPSEND
  delay(1000);
  while(esp8266.available())
  {
      //Serial.write(esp8266.read());
      esp8266.read();
      delay(10);
  }
  
  
  esp8266.println(data1); delay(1);
  esp8266.println(data2); delay(1);
  esp8266.println(data3); delay(1);
  esp8266.println(data4); delay(1);
  esp8266.println(data5); delay(1);
  esp8266.println();  delay(1); esp8266.flush();

  startTimeDataCapture = millis();
  while(1)
  {
    if(esp8266.available())
      inputBuffer += (char)esp8266.read();
      
    if(inputBuffer.indexOf("CLOSED")> 0 || millis() - startTimeDataCapture > 10000) //The server sends a close after a successful transmission. In case that didn't come (net failure, server failure whatever) then don't wait more than 20 seconds
    {
      stringComplete = true;
      //Serial.println(inputBuffer);
      //delay(1);
      break;
    }
  }

  //check if data came from server
  if(stringComplete)
  {
    inputBufferIndex = inputBuffer.indexOf("led_1=");
    if(inputBufferIndex > -1)
      led1Status = (int)(inputBuffer[inputBufferIndex+6]-'0');  // int conversion required else it was being considered as string by the codes
          
    inputBufferIndex = inputBuffer.indexOf("led_2=");
    if(inputBufferIndex > -1)
      led2Status = (int)(inputBuffer[inputBufferIndex+6]-'0');

    if(led1Status == 1)
    {
      led1Status = 1;
    }
    else
       if(led1Status == 0)
        {
          led1Status = 0;
        }
    
    if(led2Status == 1)
    {
      led2Status = 1;
    }
    else
       if(led2Status == 0)
        {
          led2Status = 0;
        }
  
    digitalWrite(led1Pin,led1Status);
    digitalWrite(led2Pin,led2Status);

    stringComplete = false;
    inputBuffer = "";
  }  
  else
  {
    esp8266.println("AT+CIPCLOSE=4"); // if for any reason  the server didn't reply properly, then close the connection
  }
  delay(5000); // wait 5 secs before making next server call
}

In future revision will implement exception handling (e.g – if the wi-fi is not found then go to sleep and try after certain intervals till connection is established, and only after connection is established move to the next step)

PHP Socket Client

This is a simple client that is running two different requests. One at every 2 seconds and another every 5 minutes. The 2 second one retrieved data from server and the 5 minute one sends data to server.

<?php
set_time_limit(0);
ob_implicit_flush();

$host    = "xxx.xxx.xxx.xxx";
$port    = 1250;

$lastUpdate = time();

while(1)
{
    if(time() - $lastUpdate > 300) //if 5 minutes elapsed
    {
        $message = "action=4512|temp=29.67|paM=10025.69|paH=125.69|led1=1|led2=0\r\n"; // the data to be sent separated by | The \r\n is important - it will tell the server that the string/data ends there
        // create socket
        $socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socket\n");
        // connect to server
        $result = socket_connect($socket, $host, $port) or die("Could not connect to server\n");  
        
        // send command/query to server
        socket_write($socket, $message, strlen($message)) or die("Could not send data to server\n");
        // get server response
        $result = socket_read ($socket, 1024, PHP_NORMAL_READ) or die("Could not read server response\n"); // 1024 is the max bytes that the socket will read if no \r\n is encountered. For the \n\r terminator PHP_NORMAL_READ is needed.
        echo "Reply From Server: ".$result."\n";
        
        // close socket
        socket_close($socket);
        
        $lastUpdate = time();
    }
    else
    {
        $message = "action=1223\r\n";
        // create socket
        $socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socket\n");
        // connect to server
        $result = socket_connect($socket, $host, $port) or die("Could not connect to server\n");  
        
        // send command/query to server
        socket_write($socket, $message, strlen($message)) or die("Could not send data to server\n");
        // get server response
        $result = socket_read ($socket, 1024, PHP_NORMAL_READ) or die("Could not read server response\n");
        echo "Reply From Server: ".$result."\n";
        
            // close socket
        socket_close($socket);
    }
    
    flush(); //may be this can be removed
    sleep(2);
    flush();
}
?>

 

PHP Socket Server – Running as Daemon and Multiple Connections

Code Courtesy: lars at opdenkamp dot eu

A socket server written in PHP. This can accept multiple connections and runs as a daemon.

pcntl_fork() is thing here that is making this all possible.

<?php
/**
  * Listens for requests and forks on each connection
  */

$__server_listening = true;

//error_reporting(E_ALL);
set_time_limit(0);
ob_implicit_flush();
declare(ticks = 1);

become_daemon();

/* nobody/nogroup, change to your host's uid/gid of the non-priv user */
change_identity(1000, 1000);

/* handle signals */
pcntl_signal(SIGTERM, 'sig_handler');
pcntl_signal(SIGINT, 'sig_handler');
pcntl_signal(SIGCHLD, 'sig_handler');

/* change this to your own host / port */
server_loop("192.168.0.1", 1250);

/**
  * Change the identity to a non-priv user
  */
function change_identity( $uid, $gid )
{
    if( !posix_setgid( $gid ) )
    {
        print "Unable to setgid to " . $gid . "!\n";
        exit;
    }

    if( !posix_setuid( $uid ) )
    {
        print "Unable to setuid to " . $uid . "!\n";
        exit;
    }
}

/**
  * Creates a server socket and listens for incoming client connections
  * @param string $address The address to listen on
  * @param int $port The port to listen on
  */
function server_loop($address, $port)
{
    GLOBAL $__server_listening;

    if(($sock = socket_create(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        echo "failed to create socket: ".socket_strerror($sock)."\n";
        exit();
    }

    if(($ret = socket_bind($sock, $address, $port)) < 0)
    {
        echo "failed to bind socket: ".socket_strerror($ret)."\n";
        exit();
    }

    if( ( $ret = socket_listen( $sock, 0 ) ) < 0 )
    {
        echo "failed to listen to socket: ".socket_strerror($ret)."\n";
        exit();
    }

    socket_set_nonblock($sock);
   
    echo "waiting for clients to connect\n";

    while ($__server_listening)
    {
        $connection = @socket_accept($sock);
        if ($connection === false)
        {
            usleep(100);
        }elseif ($connection > 0)
        {
            handle_client($sock, $connection);
        }else
        {
            echo "error: ".socket_strerror($connection);
            die;
        }
    }
}

/**
  * Signal handler
  */
function sig_handler($sig)
{
    switch($sig)
    {
        case SIGTERM:
        case SIGINT:
            exit();
        break;

        case SIGCHLD:
            pcntl_waitpid(-1, $status);
        break;
    }
}

/**
  * Handle a new client connection
  */
function handle_client($ssock, $csock)
{
    GLOBAL $__server_listening;

    $pid = pcntl_fork();

    if ($pid == -1)
    {
        /* fork failed */
        echo "fork failure!\n";
        die;
    }elseif ($pid == 0)
    {
        /* child process */
        $__server_listening = false;
        socket_close($ssock);
        interact($csock);
        socket_close($csock);
    }else
    {
        socket_close($csock);
    }
}

function interact($socket)
{
    $conn = mysql_connect("localhost","xxxxxxxx","xxxxxxxxxxx");
    if(!$conn)
    {
        echo "Error: failed to connect DB";
        die();
    }
    
    if(!mysql_select_db("xxxxxxxx",$conn))
    {
        echo "Error: failed to connect DB";
        die();
    }
    
    // read client input
    $input = socket_read($socket, 1024, PHP_NORMAL_READ);
    
    $buff = explode("|",$input);
    $len = count($buff);
    $temp = explode("=",$buff[0]);
    $temp[1] = intval($temp[1]);
    if($temp[0]!="action" && ($temp[1]!=1 || $temp[1]!=2 ))  //1=read 2=write -- these are just random numbers and has no other significance.
    {
        $output = "Error\r\n";
    } 

    
    if($temp[1] == 1)
    {
        $result = mysql_query("select * from led_status");
        $rows = mysql_fetch_array($result);
        $output = "led_1=".$rows['led_1']."|led_2=".$rows['led_2']."\r\n";
    }

    if($temp[1] == 2)
    {
        $queryW = "insert into weather set ";
        $queryL = "update led_status set ";

        for($i=1; $i<$len; $i++)
        {
            $temp = explode("=",$buff[$i]);
            switch($temp[0])
            {
                   case 'temp':
                    $queryW .= "temperature=" . floatval($temp[1]).", ";
                break;
                
                case 'paH':
                    $queryW .= "paH=" . floatval($temp[1]) .", ";    
                break;
                
                case 'paM':
                    $queryW .= "paM=" . floatval($temp[1]).", ";
                break;
                
                case 'led_1':
                    $queryL .= "led_1" . floatval($temp[1]) .", ";    
                break;
                
                case 'led_2':
                    $queryL .= "led_2=" . float_val($temp[1]).", ";        
            }
        }        
        
        $queryW .= " time=".time();
        $queryL .= " time=".time();
        
        mysql_query($queryL);
        mysql_query($queryW);
        
        $output = "Update Success\r\n";
    }
            
    /* TALK TO YOUR CLIENT */ 
    socket_write($socket,$output, strlen($output));    
    mysql_close();
}

/**
  * Become a daemon by forking and closing the parent
  */
function become_daemon()
{
    $pid = pcntl_fork();
   
    if ($pid == -1)
    {
        /* fork failed */
        echo "fork failure!\n";
        exit();
    }elseif ($pid)
    {
        /* close the parent */
        exit();
    }else
    {
        /* child becomes our daemon */
        posix_setsid();
        chdir('/');
        umask(0);
        return posix_getpid();

    }
}
?>

BMP-180 Digital Barometric Pressure Sensor

BMP-180 is a compact and cheap Digital Barometric Pressure Sensor. Below is an image of the breakout board commonly available on ebay

BMP 180 Digital Barometric Pressure Sensor

There is some confusing information about the required voltage, so safest would be to go with 3.3v. As per datasheet (download here) from Bosch, the chip manufacturer, the max voltage is 3.6v

It has a temperature sensor also inbuilt.

The library from Sparkfun is very good. It can be found here on Github (another is under development). It also has a very good example sketch.  The library has been uploaded here to ensure availability.

Below is a code snippet for reading the temperature and pressure

#include <SFE_BMP180.h>
.............
.............
SFE_BMP180 pressure;
double T,P,temp,paH,paM;
...........
...........
pressure.begin();
...........
...........

// You must first get a temperature measurement to perform a pressure reading.
// Start a temperature measurement:
// If request is successful, the number of ms to wait is returned.
// If request is unsuccessful, 0 is returned.
status = pressure.startTemperature();
if (status != 0)
{
  // Wait for the measurement to complete:
  delay(status);

  // Retrieve the completed temperature measurement:
  // Note that the measurement is stored in the variable T.
  // Function returns 1 if successful, 0 if failure.

  status = pressure.getTemperature(T);
  if (status != 0)
  {
    // Print out the measurement:
    temp = T;

    // Start a pressure measurement:
    // The parameter is the oversampling setting, from 0 to 3 (highest res, longest wait).
    // If request is successful, the number of ms to wait is returned.
    // If request is unsuccessful, 0 is returned.

    status = pressure.startPressure(3);
    if (status != 0)
    {
      // Wait for the measurement to complete:
      delay(status);

      // Retrieve the completed pressure measurement:
      // Note that the measurement is stored in the variable P.
      // Note also that the function requires the previous temperature measurement (T).
      // (If temperature is stable, you can do one temperature measurement for a number of pressure measurements.)
      // Function returns 1 if successful, 0 if failure.

      status = pressure.getPressure(P,T);
      if (status != 0)
      {
        // Print out the measurement:
        paM = P;
        paH = P*0.0295333727;
      }
      else
      {
        paM = -1;
        paH = -1;
      }
    }
    else
    {
        paM = -1;
        paH = -1;
    }
  }
  else
  {
    temp = -1;
  }
}
else
{
  temp = -1;
}
...........
...........

Realtime Charts / Graphs

CanvasJS  provides a very developer friendly chat or graph library. The library is based on HTML 5 and JS. And can also be used for displaying realtime charts or graphs also.

There are various types of charts/graphs available.

Below are some useful codes

Frontend code:
<?php
$conn = mysql_connect("localhost","xxxxxxxxx","xxxxxxxxx");
if(!$conn)
{
    echo "Error: failed to connect DB Server";
    die();
}

if(!mysql_select_db("xxxxxxxxx",$conn))
{
    echo "Error: failed to connect DB";
    die();
}

$jsonArray1 = array();
$i=0;
$result = mysql_query("select * from weather_log");
while($rows = mysql_fetch_array($result))
{
    $jsonArray1[$i] = array(date("Y,m,d,H,i",$rows['timestamp']), floatval($rows['temperature']));
}
?>
<html>
  <head>
  <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
  <script type="text/javascript">
      var chart;
      window.onload = function () {
        chart = new CanvasJS.Chart("chartContainer",
        {
          title:{
          text: "Temperature"
          },
           data: [
          {
            type: "line",
    
            dataPoints: [
            <?php
                for($j=0;$j<$i;$j++)
                {
           ?>
                       { x: new Date(<?php echo $jsonArray1[$j][0] ?>), y: <?php echo $jsonArray1[$j][1] ?> } <?php echo $j<$i-1?"," :"" ?>
           <?php         
                }
            ?>            
            ]
          }
          ]
        });
    
        chart.render();
      }
      
    function updateTemp() 
    {
        var str = JSON.parse(updateData("t"));
        var date = str[1].split(",");
        chart.options.data[0].dataPoints.push({x : new Date(date[0],date[1],date[2],date[3],date[4]),  y : parseFloat(str[0]) });
          
        chart.render();         
    };
        
    function updateData(type)
    {
        var xmlhttp = new XMLHttpRequest();
        xmlhttp.open("GET", "dataPlotter.php?q=" + type, false);
        xmlhttp.send();
        return xmlhttp.responseText;
    }
    
    setInterval("updateTemp()",360000);    
  </script>
  </head>

  <body>

    <!--Div that will hold the chart-->
    <div id="chartContainer" style="height: 300px; width: 100%;"></div>
    
    
    <script src="canvasjs.min.js"></script>
    <script src="jquery.canvasjs.min.js"></script>
    
  </body>
</html>
Backend code (dataPlotter.php in above snippet)
$result = mysql_query("select temperature,timestamp from weather_log order by timestamp desc limit 0,1");
$rows = mysql_fetch_array($result);

header('Content-Type: application/json');
echo json_encode(array($rows['temperature'],date("Y,m,d,H,i",$rows['timestamp'])));

 

ESP8266 ESP-01 – Part 2 – Useful AT Commands And Their Outputs

Below are some AT commands for ESP8266 and their outputs

AT
OK
AT+GMR
This will display firmware version and some other details 
AT+CIPMUX=1 
OK
AT+CWMODE=3 
OK
AT+CWJAP="WIRELESS-ROUTER","password"
[WIFI DISCONNECTED] (if it is already connected)
WIFI CONNECTED
WIFI GOT IP
OK
AT+CIPSTART=4,"TCP","x.x.x.x",80
4,CONNECT
OK
AT+CIPSEND=4,205
OK
> [at this point HTTP request will be made, read below for details]
Recv 205 bytes
SEND OK
+IPD,4,203:HTTP/1.1 200 OK
Date: Sun, 14 Feb 2016 20:33:16 GMT
Server: Apache/2.4.7 (Ubuntu)
X-Powered-By: PHP/5.5.9-1ubuntu4.14
Content-Length: 15
Connection: close
Content-Type: text/html

led_1=0|led_2=14,CLOSED

[The blue colored text above is what the server has sent in reply to the HTTP request]
AT+UART_CUR=2400,8,1,0,0
OK

[This command work with AT ver 6.0 and SDK ver 1.5.2. The changes will be temporary and will be restored to default on resetting. Use ]
AT+UART_DEF=2400,8,1,0,0

[This will make the change permanent. In case things gets wrong then reflash]

If AT+UART doesn't work then use 
AT+IPR

 

An extensive guide can be found here
https://github.com/espressif/ESP8266_AT/wiki/CWSAP

https://docs.espressif.com/projects/esp-at/en/latest/AT_Command_Set/Basic_AT_Commands.html

 

ESP8266 ESP-01 – Part 1 – Flashing and AT commands

This article is about the one that looks like this (aka ESP-01).

esp8266-esp-01-wifi-module-for-iot

 

Flasher version is 2.3
Firmware version is 1.5

Firmware update might be necessary just after purchase. Without firmware update mine was not able to connect to Wi-fi routers (though they were able to find them)

The current firmware available for this is “ESP8266_AT_v0.51”. The direct link to the download http://bbs.espressif.com/viewtopic.php?f=46&t=1451 . The download is at the bottom of the page as an Attachment.

firware files and readme

The flasher (for flashing firmware) can be found here http://bbs.espressif.com/viewtopic.php?f=57&t=433. The .rar version contains the necessary files to update the firmware.

WARNING: read the readme file that came with the firmware.

esp8266-flasher

Please note New chips need DOUT specifically, whereas old ones work with both QIO and DOUT

 Latest Flasher and Firmware Downloads (6th Feb, 2016):

 

Pin configuration of the module

esp8266 - pin

IMPORTANT NOTES:

  • This board runs on 3.3v
  • The default Baud rate is 115200
  • Boot errors are output over 74800. This is default and fixed.
  • For the RX TX line voltage divider using resistors doesn’t work. Using a 150 ohms in series for now, waiting for my Logic Level converter. But then so far (many years now) direct connection didn’t damage the ESP-01.

 

Flashing

  1. Used an Arduino Uno to flash the firmware.
  2. Upload a blank sketch to the Arduino.
  3. The module’s RX will go to Arduino RX and similarly TX will go TX.
  4. GPIO_0 will go to GND
  5. VCC and CH_PD will go to the 3.3v supply line
  6. Load the flasher
  7. Mine one came with “Ai-Cloud insid8” written. This module has a Flash size of 8Mbit: 512KB+512KB. QuadIO and 26MHZ crystal.
  8. Select the appropriate files in the “Download Path Config” section in the flasher tool. Some of the addresses might also need to be adjusted. READ the readme file that came with the firmware.
  9. Select the COM port on which Arduino is connected and the set the Baud rate to 115200 (the default of this board)
  10. Press start. If all goes well it will show finish to the left of the “Start” and “Stop” button
  11. If it fails – press “Stop”. Reset the board by Grounding RESET pin. And press Start again
  12. If the flashing is going on properly then the TX light of Arduino and the Blue light of the module will flash.
  13. Once firmware has been flashed disconnect the GPIO_0 pin from GND. Reset the module and start working

Useful links:
http://www.electrodragon.com/w/Category:ESP8266_Firmware_and_SDK

 

AT Commands

  1. Used Arduino Serial monitor for sending AT commands to the Module.
  2. The RX and TX pin configuration will remain same as above.
  3. Start with the AT command.
  4. List of some useful AT commands : http://www.pridopia.co.uk/pi-doc/ESP8266ATCommandsSet.pdf

 

Notes

  • After flashing the default baud rate becomes 115200. And also the CWMODE might need to be changed to 1 or 3 manually (mine somehow went to mode 2 that is AP mode)
  • If the RTOS firmware is flashed then the “user1.1024.new.2.bin” file inside the AT directory cannot be flashed – it makes the chip non-responsive.
  • The required files for RTOS firmware comes in the zip file named “AT_V0.60_on_ESP8266_NONOS_SDK_V1.5.2_20160203” and is inside “noboot” folder.

 

Updated version of this here: https://www.kolkataonweb.com/code-bank/arduino/esp-01-burning-at-rom-new-and-updated/