phpoc_man
Published © GPL3+

PHPoC, ThingSpeak, Temperature and Humidity Sensors

This project shows how to read temperature & humidity from TH02, HDC1000 or HTS221 and send ThingSpeak using ThingSpeak library for PHPoC.

BeginnerProtip6 hours1,205
PHPoC, ThingSpeak, Temperature and Humidity Sensors

Things used in this project

Hardware components

PHPoC Blue
PHPoC Blue
We can use PHPoC black instead
×1
Grove - HDC1000 Temperature&Humidity Sensor
Optional
×1
Grove TH02 Temperature & Humidity Sensor
Optional
×1
mikroBUS - HTS221 temp & humi Click
Optional
×1
PHPoC Grove Expansion Board
PHPoC Grove Expansion Board
Optional if using Grove sensor
×1
PHPoC mikroBUS Expansion Board
PHPoC mikroBUS Expansion Board
Optional if using MikroBUS sensor
×1

Software apps and online services

ThingSpeak API
ThingSpeak API

Story

Read more

Schematics

Connection

Just stack and connect it (Grove sensor to grove expansion board - I2C Grove Interface. Mikro sensor to Mikro to MikroBUS expansion Boar - any mikroBUS interface)

Code

Main task (task0.php)

PHP
This program is run in infinite loop to read and send temperature and humidity to ThingSpeak
<?php

if(_SERVER("REQUEST_METHOD"))
    exit; // avoid php execution via http request
 
include_once "/lib/sd_340.php";
include_once "/lib/sn_dns.php";
include_once "/lib/sn_http.php";
include_once "/lib/vn_thingspeak.php";
include_once "/lib/vd_th02.php";
include_once "/lib/vd_hdc1000.php";
include_once "/lib/vd_hts221.php";

define("TH02",        0); // grove Temperature&Humidity Sensor (High-Accuracy & Mini) V1.0 
define("HDC1000",    1); // grove Temperature&Humidity Sensor (HDC1000)
define("HTS221",    2); // mikro click

$my_write_api_key = "your write api key";
$my_read_api_key = "your read api key";
$my_channel_id = "your channed id";

$sensor_type = TH02; // choose sensor type here

switch($sensor_type)
{
    case TH02:
        i2c_TH02_setup(0);
        break;
    case HDC1000:
        i2c_HDC1000_setup(0);
        break;
    case HTS221:
        i2c_HTS221_setup(0);
        while(!HTS221_init())
        ;
        break;
    default:
        exit "library is not yet available for this sensor\r\n";
}

while(1)
{    
    switch($sensor_type)
    {    
        case TH02:
            $temp = TH02_read_temperature();            
            $humi = TH02_read_humidity();
            break;
            
        case HDC1000:
            $temp = HDC1000_read_temperature();            
            $humi = HDC1000_read_humidity();
            break;
            
        case HTS221:
            $temp = HTS221_read_temperature();    
            
            if(is_bool($temp))
            {
                echo "a new temperature sample is not yet available\r\n";
                usleep(500000);
                continue;
            }
            
            usleep(1000);
            
            $humi = HTS221_read_humidity();
            if(is_bool($humi))
            {
                echo "a new humidity sample is not yet available\r\n";
                usleep(500000);
                continue;
            }
    }
    
    thingspeak_set_field(1, $temp);
    thingspeak_set_field(2, $humi);
    $reval = thingspeak_write_fields($my_channel_id, $my_write_api_key); 
    
    if( $reval === OK_SUCCESS)
        echo "write successfully\r\n";
    else 
        echo "write unsuccessfully\r\n";
    
    // maximum update rate of thingspeak is 15 second
    sleep(15);
    
}
 
?>

ThingSpeak Library for PHPoC (vn_thingspeak.php)

PHP
This is ThingSpeak library for PHPoC ()
<?php

define("THINGSPEAK_URL", "api.thingspeak.com");

define("FIELDNUM_MIN",        1);
define("FIELDNUM_MAX",        8);
define("FIELDLENGTH_MAX",    255);  // Max length for a field in ThingSpeak is 255 bytes (UTF-8)

define("OK_SUCCESS",                 200); // OK / Success
define("ERR_BADAPIKEY",                 400); // Incorrect API key (or invalid ThingSpeak server address)
define("ERR_BADURL",                 404); // Incorrect API key (or invalid ThingSpeak server address)
define("ERR_OUT_OF_RANGE",            -101); // Value is out of range or string is too long (> 255 bytes)
define("ERR_INVALID_FIELD_NUM",        -201); // Invalid field number specified
define("ERR_SET_FIELD_NOT_CALLED",    -210); // thingspeak_set_field() was not called before thingspeak_write_fields()
define("ERR_CONNECT_FAILED",        -301); // Failed to connect to ThingSpeak
define("ERR_UNEXPECTED_FAIL",        -302); // Unexpected failure during write to ThingSpeak
define("ERR_BAD_RESPONSE",            -303); // Unable to parse response
define("ERR_TIMEOUT",                -304); // Timeout waiting for server to respond
define("ERR_NOT_INSERTED",            -401); // Point was not inserted (most probable cause is the rate limit of once every 15 seconds)

$next_write_fields = array("", "", "", "", "", "", "", "");
$next_write_latitude = "";
$next_write_longitude = "";
$next_write_elevation = "";
$next_write_status = "";
$next_write_twitter = "";
$next_write_tweet = "";
$next_write_created_at = "";

function json_get_value($json_str, $key, &$value, $offset = 0)
{
    $value = "";
    
    if(strlen($json_str) == 0)
        return false;
    
    $search = "\"" . $key . "\":";
    
    $from_pos = strpos($json_str, $search, $offset);
    
    if($from_pos === false)
        return false;
    
    $from_pos += strlen($search);
    
    while($json_str[$from_pos] == " ")
        $from_pos++;
    
    $to_pos = $from_pos;
    $start_char = $json_str[$from_pos];
    
    if($start_char == "[" || $start_char == "{")
    {
        if($start_char == "[")
            $end_char = "]";
        else
            $end_char = "}";
        
        $start_count = 0;
        $end_count = 0;
        
        for($i = $from_pos; $i < strlen($json_str); $i++)
        {
            if($json_str[$i] == $start_char)
                $start_count++;
            if($json_str[$i] == $end_char)
                $end_count++;
            
            if($end_count == $start_count)
            {
                $to_pos = $i;
                break;
            }
        }
    }
    else
    {
        $pos1 = strpos($json_str, ",", $from_pos);
        $pos2 = strpos($json_str, "}", $from_pos);
        
        if($pos1 === false)
            $to_pos = $pos2;
        else if($pos2 === false)
            $to_pos = $pos1;
        else 
            $to_pos = ($pos1 > $pos2) ? $pos2: $pos1;
        
        $to_pos--;
    }
    
    if($to_pos === false)
        return false;
    
    $length = $to_pos - $from_pos + 1;
    
    $value = substr($json_str, $from_pos, $length);
    $value = rtrim(ltrim($value, "\""), "\"");
    
    return $to_pos;
}

function thingspeak_setup($udp_id, $tcp_id, $dns_server = "", $ip6 = false)
{
    http_setup($udp_id, $tcp_id, $dns_server, $ip6);
}

/**
*@brief: Write a raw POST to a ThingSpeak channel
*@param: $channel_id: Channel number
*@param: $post_msg: Raw URL to write to ThingSpeak as a String.  See the documentation at https://thingspeak.com/docs/channels#update_feed.
*@param: $write_api_key: Write API key associated with the channel. If you share code with others, do  not share this key
*@return: status code.
*@remark: This is low level functionality that will not be required by most users.
*@example code:
    $post_msg = "field1=23&created_at=2017-03-23T23:59:59";
    thingspeak_write_raw($my_channel_id, $post_msg, $my_write_api_key);
*/
function thingspeak_write_raw($channel_id, $post_msg, $write_api_key)
{
    $post_msg .= "&headers=false\n";
    $cnt_len = strlen($post_msg);
    
    http_add_header("Content-Type: application/x-www-form-urlencoded\r\n");
    http_add_header("Content-Length: $cnt_len\r\n");
    http_add_header("X-THINGSPEAKAPIKEY: $write_api_key\r\n");
    
    $rsp_head = http_request("post", THINGSPEAK_URL . "/update", $post_msg);
    
    //echo $rsp_head;
    
    if($rsp_head === "")
        return ERR_CONNECT_FAILED;
    
    $status = http_status($rsp_head);
    
    $rsp_body = "";
    $rbuf = "";
    
    while(http_recv($rbuf))
        $rsp_body .= $rbuf;
    
    http_close();
    
    if($status == OK_SUCCESS)
    {
        $entry_id = (int)$rsp_body;
        
        if($entry_id == 0)
        {
            // ThingSpeak did not accept the write
            $status = ERR_NOT_INSERTED;
        }
    }
    
    return $status;
}

/**
*@brief: Read a raw response from a ThingSpeak channel
*@param: $rsp_body: buffer to store the http body
*@param: $channel_id: Channel number
*@param: $url_suffix: Raw URL to write to ThingSpeak as a String.  See the documentation at https://thingspeak.com/docs/channels#get_feed
*@param: $read_api_key: Read API key associated with the channel. Igrore this param if reading a public channel. If you share code with others, do  not share this key
*@return: status code.
*@remark: This is low level functionality that will not be required by most users.
*@example code:
    $response = "";
    thingspeak_read_raw($response, $my_channel_id, "/feeds/last.txt", $my_read_api_key);
    echo $response;
*/
function thingspeak_read_raw(&$rsp_body, $channel_id, $url_suffix, $read_api_key = "")
{
    $rsp_body = "";
    $uri = THINGSPEAK_URL . "/channels/$channel_id" . $url_suffix;
    
    http_add_header("X-THINGSPEAKAPIKEY: $read_api_key\r\n");
    
    $rsp_head = http_request("get", $uri);
    
    //echo $rsp_head;
    
    if($rsp_head === "")
        return ERR_CONNECT_FAILED;
    
    $status = http_status($rsp_head);
    
    $rbuf = "";
    
    while(http_recv($rbuf))
        $rsp_body .= $rbuf;
    
    http_close();
    
    if($status != OK_SUCCESS)
    {
        $rsp_body = "";
    }
    
    return $status;
}

/**
*@brief: Write data (any type) to a single field in a ThingSpeak channel
*@param: $channel_id: Channel number
*@param: $field: Field number (1-8) within the channel to write to.
*@param: $value: Value to write (any type).  ThingSpeak limits this field to 255 bytes. 
*@param: $write_api_key: Write API key associated with the channel. If you share code with others, do  not share this key
*@return: status code.
*@remark: Visit https://thingspeak.com/docs/channels for more information about channels, API keys, and fields.  ThingSpeak limits the number of writes to a channel to once every 15 seconds.
*@example code:
    thingspeak_write_field($my_channel_id, 1, 25, $my_write_api_key);
    thingspeak_write_field($my_channel_id, 3, "Too Hot!", $my_write_api_key);
*/
function thingspeak_write_field($channel_id, $field, $value, $write_api_key)
{
    $post_msg = "field$field=$value";
    return thingspeak_write_raw($channel_id, $post_msg, $write_api_key);
}

/**
*@brief: Set the value of a single field that will be part of a multi-field update. To write multiple fields at once, call thingspeak_set_field() for each of the fields you want to write, and then call thingspeak_write_fields()
*@param: $field: Field number (1-8) within the channel to set
*@param: $value: value to write (any type).  ThingSpeak limits this to 255 bytes.
*@return: status code.
*@example code:
    thingspeak_set_field(1, 1.2);
    thingspeak_set_field(2, 15);
    thingspeak_set_field(3, "state ON");
    thingspeak_write_fields($my_channel_id, $my_write_api_key);
*/
function thingspeak_set_field($field, $value)
{
    global $next_write_fields;
    
    $str_value = "$value";
    
    if($field < FIELDNUM_MIN || $field > FIELDNUM_MAX) 
        return ERR_INVALID_FIELD_NUM;
    
    // Max # bytes for ThingSpeak field is 255 (UTF-8)
    if(strlen($str_value) > FIELDLENGTH_MAX) 
        return ERR_OUT_OF_RANGE;
    
    $next_write_fields[$field - 1] = $str_value;
    
    return OK_SUCCESS;
}

/**
*@brief: Set the latitude of a multi-field update. To record latitude, longitude and elevation of a write, call thingspeak_set_field() for each of the fields you want to write, thingspeak_set_latitude() / thingspeak_set_longitude() / thingspeak_set_elevation(), and then call thingspeak_write_fields()
*@param: $latitude: Latitude of the measurement (degrees N, use negative values for degrees S)
*@return: status code.
*@see thingspeak_set_field(), thingspeak_set_longitude(), thingspeak_set_elevation(), thingspeak_write_fields()
*@example code:
    thingspeak_set_field(1, 1.2);
    thingspeak_set_field(2, 15);
    thingspeak_set_field(3, "state ON");
    thingspeak_set_latitude(42.2833);
    thingspeak_set_longitude(-71.3500);
    thingspeak_set_elevation(100);
    thingspeak_write_fields($my_channel_id, $my_write_api_key);
*/
function thingspeak_set_latitude($latitude)
{
    global $next_write_latitude;
    
    $next_write_latitude = "$latitude";
    return OK_SUCCESS;
}

/**
*@brief: Set the longitude of a multi-field update. To record latitude, longitude and elevation of a write, call thingspeak_set_field() for each of the fields you want to write, thingspeak_set_latitude() / thingspeak_set_longitude() / thingspeak_set_elevation(), and then call thingspeak_write_fields()
*@param: $longitude: Longitude of the measurement (degrees E, use negative values for degrees W)
*@return: status code.
*@see thingspeak_set_field(), thingspeak_set_latitude(), thingspeak_set_elevation(), thingspeak_write_fields()
*@example code:
    thingspeak_set_field(1, 1.2);
    thingspeak_set_field(2, 15);
    thingspeak_set_field(3, "state ON");
    thingspeak_set_latitude(42.2833);
    thingspeak_set_longitude(-71.3500);
    thingspeak_set_elevation(100);
    thingspeak_write_fields($my_channel_id, $my_write_api_key);
*/
function thingspeak_set_longitude($longitude)
{
    global $next_write_longitude;
    
    $next_write_longitude = "$longitude";
    return OK_SUCCESS;
}

/**
*@brief: Set the elevation of a multi-field update. To record latitude, longitude and elevation of a write, call thingspeak_set_field() for each of the fields you want to write, thingspeak_set_latitude() / thingspeak_set_longitude() / thingspeak_set_elevation(), and then call thingspeak_write_fields()
*@param: $elevation: Elevation of the measurement (meters above sea level)
*@return: status code.
*@see thingspeak_set_field(), thingspeak_set_latitude(), thingspeak_set_longitude(), thingspeak_write_fields()
*@example code:
    thingspeak_set_field(1, 1.2);
    thingspeak_set_field(2, 15);
    thingspeak_set_field(3, "state ON");
    thingspeak_set_latitude(42.2833);
    thingspeak_set_longitude(-71.3500);
    thingspeak_set_elevation(100);
    thingspeak_write_fields($my_channel_id, $my_write_api_key);
*/
function thingspeak_set_elevation($elevation)
{
    global $next_write_elevation;
    
    $next_write_elevation = "$elevation";
    return OK_SUCCESS;
}

/**
*@brief: Set the status of a multi-field update. To record a status message on a write, call thingspeak_set_status() then call thingspeak_write_fields(). Use status to provide additonal details when writing a channel update.
*@param: $status: String to write (UTF8).  ThingSpeak limits this to 255 bytes.
*@return: status code.
*@see thingspeak_write_fields()
*@example code:
    thingspeak_set_field(1, 1.2);
    thingspeak_set_field(2, 15);
    thingspeak_set_field(3, "state ON");
    thingspeak_set_status("Too Cold!");
    thingspeak_write_fields($my_channel_id, $my_write_api_key);
*/
function thingspeak_set_status($status)
{
    global $next_write_status;
    
    // Max # bytes for ThingSpeak field is 255 (UTF-8)
    if(strlen($status) > FIELDLENGTH_MAX) 
        return ERR_OUT_OF_RANGE;
    
    $next_write_status = $status;
    return OK_SUCCESS;
}

/**
*@brief: Set the Twitter account and message to use for an update to be tweeted. To send a message to twitter call thingspeak_set_twitter_tweet() then call thingspeak_write_fields()
*@param: $twitter: Twitter account name as a String.
*@param: $tweet: Twitter message as a String (UTF-8) limited to 140 character.
*@return: status code.
*@remark: Prior to using this feature, a twitter account must be linked to your ThingSpeak account. Do this by logging into ThingSpeak and going to Apps, then ThingTweet and clicking Link Twitter Account.
*@see thingspeak_write_fields()
*@example code:
    thingspeak_set_field(1, 1.2);
    thingspeak_set_field(2, 15);
    thingspeak_set_field(3, "state ON");
    thingspeak_set_status("Too Cold!");
    thingspeak_set_twitter_tweet("YourTwitterAccountName", "Too Hot!");
    thingspeak_write_fields($my_channel_id, $my_write_api_key);
*/
function thingspeak_set_twitter_tweet($twitter, $tweet)
{
    global $next_write_twitter;
    global $next_write_tweet;
    
    if((strlen($twitter) > FIELDLENGTH_MAX) || (strlen($tweet) > FIELDLENGTH_MAX)) 
        return ERR_OUT_OF_RANGE;
    
    $next_write_twitter = $twitter;
    $next_write_tweet = $tweet;
    return OK_SUCCESS;
}

/**
*@brief: Set the created-at date of a multi-field update. To record created-at of a write, call thingspeak_set_field() for each of the fields you want to write, thingspeak_set_created_at(), and then call thingspeak_write_fields()
*@param: $created_at Desired timestamp to be included with the channel update as a String.  The timestamp string must be in the ISO 8601 format. Example "2017-03-23T13:59:59"
*@return: status code.
*@remark: Timezones can be set using the timezone hour offset parameter. For example, a timestamp for Eastern Standard Time is: "2017-01-12 13:22:54-05".  If no timezone hour offset parameter is used, UTC time is assumed.
*@see thingspeak_set_field(), thingspeak_write_fields()
*@example code:
    thingspeak_set_field(1, 1.2);
    thingspeak_set_field(2, 15);
    thingspeak_set_field(3, "state ON");
    thingspeak_set_status("Too Cold!");
    thingspeak_set_created_at("2017-03-23T13:59:59");
    thingspeak_write_fields($my_channel_id, $my_write_api_key);
*/
function thingspeak_set_created_at($created_at)
{
    global $next_write_created_at;
    
    $next_write_created_at = $created_at;
    
    return OK_SUCCESS;
}

/**
*@brief: Write a multi-field update. Call thingspeak_set_field() for each of the fields you want to write, thingspeak_set_latitude() / thingspeak_set_longitude() / thingspeak_set_elevation(), and then call thingspeak_write_fields()
*@param: $channel_id: Channel number
*@param: $write_api_key: Write API key associated with the channel. If you share code with others, do  not share this key
*@return: status code.
*@see thingspeak_set_field(), thingspeak_set_latitude(), thingspeak_set_longitude(), thingspeak_set_elevation()
*@example code:
    thingspeak_set_field(1, 1.2);
    thingspeak_set_field(2, 15);
    thingspeak_set_field(3, "state ON");
    thingspeak_set_latitude(42.2833);
    thingspeak_set_longitude(-71.3500);
    thingspeak_set_elevation(100);
    thingspeak_write_fields($my_channel_id, $my_write_api_key);
*/
function thingspeak_write_fields($channel_id, $write_api_key)
{
    global $next_write_fields;
    global $next_write_latitude;
    global $next_write_longitude;
    global $next_write_elevation;
    global $next_write_status;
    global $next_write_twitter;
    global $next_write_tweet;
    global $next_write_created_at;
    
    $post_msg = "";
    
    $is_first_item = true;
    
    for($i = 0; $i < 8; $i++)
    {
        if($next_write_fields[$i] != "")
        {
            if(!$is_first_item)
            {
                $post_msg .= "&";
            }
            $field = $i + 1;
            $post_msg .= "field$field=" . $next_write_fields[$i];
            $is_first_item = false;
            $next_write_fields[$i] = "";
        }
    }

    if($next_write_latitude != "")
    {
        if(!$is_first_item)
        {
            $post_msg .= "&";
        }
        $post_msg .= "lat=" . $next_write_latitude;
        $is_first_item = false;
        $next_write_latitude = "";
    }

    if($next_write_longitude != "")
    {
        if(!$is_first_item)
        {
            $post_msg .= "&";
        }
        $post_msg .= "long=" . $next_write_longitude;
        $is_first_item = false;
        $next_write_longitude = "";
    }


    if($next_write_elevation != "")
    {
        if(!$is_first_item)
        {
            $post_msg .= "&";
        }
        $post_msg .= "elevation=" . $next_write_elevation;
        $is_first_item = false;
        $next_write_elevation = "";
    }
    
    if($next_write_status != "")
    {
        if(!$is_first_item)
        {
            $post_msg .= "&";
        }
        $post_msg .= "status=" . $next_write_status;
        $is_first_item = false;
        $next_write_status = "";
    }
    
    if($next_write_twitter != "")
    {
        if(!$is_first_item)
        {
            $post_msg .= "&";
        }
        $post_msg .= "twitter=" . $next_write_twitter;
        $is_first_item = false;
        $next_write_twitter = "";
    }
    
    if($next_write_tweet != "")
    {
        if(!$is_first_item)
        {
            $post_msg .= "&";
        }
        $post_msg .= "tweet=" . $next_write_tweet;
        $is_first_item = false;
        $next_write_tweet = "";
    }
    
    if($next_write_created_at != "")
    {
        if(!$is_first_item)
        {
            $post_msg .= "&";
        }
        $post_msg .= "created_at=" . $next_write_created_at;
        $is_first_item = false;
        $next_write_created_at = "";
    }
    
    
    if($is_first_item)
    {
        // thingspeak_set_field() was not called before write_fields
        return ERR_SET_FIELD_NOT_CALLED;
    }

    return thingspeak_write_raw($channel_id, $post_msg, $write_api_key);
}

/**
*@brief: Read the latest field value from a ThingSpeak channel
*@param: $buf: buffer to store the field value
*@param: $channel_id: Channel number
*@param: $field: Field number (1-8) within the channel to read from.
*@param: $read_api_key: Read API key associated with the channel. Igrore this param if reading a public channel. If you share code with others, do  not share this key
*@return: status code.
*@example code:
    $value = "";
    $status = thingspeak_read_field($value, $my_channel_id, 1, $my_read_api_key);
    echo "status: $status\r\n";
    echo "value: $value\r\n";
*/
function thingspeak_read_field(&$buf, $channel_id, $field, $read_api_key = "")
{
    if($field < FIELDNUM_MIN || $field > FIELDNUM_MAX) 
        return ERR_INVALID_FIELD_NUM;
    
    return thingspeak_read_raw($buf, $channel_id, "/fields/$field/last", $read_api_key);
}

/**
*@brief: Read the latest status from a ThingSpeak channel
*@param: $channel_id: Channel number
*@param: $read_api_key: Read API key associated with the channel. Igrore this param if reading a public channel. If you share code with others, do  not share this key
*@return: Value read (UTF8 string). An empty string is returned if there was no status written to the channel or in case of an error.  Use getLastthingspeak_read_status() to get more specific information.
*@example code:
    $status  = thingspeak_read_status($my_channel_id, $my_read_api_key);
    echo "Latest status is: $status"; 
*/
function thingspeak_read_status($channel_id, $read_api_key = "")
{
    $buf = "";
    
    $ret = thingspeak_read_raw($buf, $channel_id, "/feeds/last.txt?status=true", $read_api_key);
    
    $status = "";
    
    if($ret == OK_SUCCESS)
        json_get_value($buf, "status", $status);
    
    return $status;
}

/**
*@brief: Read the created-at timestamp associated with the latest update to a ThingSpeak channel
*@param: $channel_id: Channel number
*@param: $read_api_key: Read API key associated with the channel. Igrore this param if reading a public channel. If you share code with others, do  not share this key
*@return: Value read (UTF8 string). An empty string is returned if there was no created-at timestamp written to the channel or in case of an error.  Use getLastthingspeak_read_status() to get more specific information.
*@example code:
    $created_at = thingspeak_read_created_at($my_channel_id, $my_read_api_key);
    echo "Latest update timestamp is: $created_at"; 
*/
function thingspeak_read_created_at($channel_id, $read_api_key = "")
{
    $buf = "";
    
    $ret = thingspeak_read_raw($buf, $channel_id, "/feeds/last.txt", $read_api_key);
    
    $created_at = "";
    
    if($ret == OK_SUCCESS)
        json_get_value($buf, "created_at", $created_at);
    
    return $created_at;
}

?>

TH02 Library (vd_th02.php)

PHP
TH02 Sensor Library
<?php

include_once "/lib/sd_340.php";

define("TH02_ADDR", 0x40);

define("REG_STATUS",       0x00); 
define("REG_DATA_H",       0x01);
define("REG_DATA_L",       0x02);
define("REG_CONFIG",       0x03);
define("REG_ID",           0x11);

define("STATUS_RDY_MASK",  0x01);    //poll RDY,0 indicate the conversion is done

define("CMD_MEASURE_HUMI", 0x01);    //perform a humility measurement
define("CMD_MEASURE_TEMP", 0x11);    //perform a temperature measurement

define("TH02_WR_REG_MODE", 0xC0);
define("TH02_RD_REG_MODE", 0x80);

$pid = 0;

function i2c_TH02_setup($i2c_id)
{
    global $pid ;
    
    $sensor_addr = sprintf("%02x", TH02_ADDR << 1);
    
    $pid = pid_open("/mmap/i2c$i2c_id");
    pid_ioctl($pid, "req reset");
    pid_ioctl($pid, "set saddr $sensor_addr");
    pid_ioctl($pid, "set mode sm");
    pid_ioctl($pid, "set role master");
}

// Generic I2C write $data to register (single byte)
function TH02_write8($addr_reg, $data)
{
    global $pid ;
    
    pid_ioctl($pid, "req reset");
    pid_ioctl($pid, "req write wait");
    //register to read
    pid_write($pid, $addr_reg, 1); 
    pid_write($pid, $data, 1); 
    
    pid_ioctl($pid, "req stop"); // stop writing data
}

// Generic I2C read registers (two bytes, LSB first)
function TH02_read16($addr_reg)
{
    global $pid ;
    
    $data_lsb = 0x00;
    $data_msb = 0x00;
    
    pid_ioctl($pid, "req reset");
    pid_ioctl($pid, "req write wait");
    // register to read
    pid_write($pid, $addr_reg, 1); 
    
    pid_ioctl($pid, "req stop"); // stop writing data
    
    pid_ioctl($pid, "req read 2"); // request to read 2 bytes
    while(pid_ioctl($pid, "get rxlen") < 2); // check received data
    
    pid_read($pid, $data_lsb, 1); // read buffer
    pid_read($pid, $data_msb, 1); // read buffer    
    
    return ($data_lsb | ($data_msb << 8));
}

function TH02_read_temperature()
{
    TH02_write8(REG_CONFIG, CMD_MEASURE_TEMP);
    
    usleep(50000);
    
    $value = TH02_read16(REG_DATA_H);
    $value = (float)($value >> 2);
    /* 
      Formula:
      Temperature(C) = (Value/32) - 50      
    */    
    $temper = ($value/32.0)-50.0;
    return $temper;
}

function TH02_read_humidity()
{
    TH02_write8(REG_CONFIG, CMD_MEASURE_HUMI);
    
    usleep(50000);
    
    $value = TH02_read16(REG_DATA_H);
    $value = (float)($value >> 4);
 
    /* 
      Formula:
      Humidity(%) = (Value/16) - 24      
    */    

    $humility = ($value/16.0)-24.0;
    
    return $humility;
}

?>

HDC1000 Library (vd_hdc1000.php)

PHP
HDC1000 Sensor Library
<?php

include_once "/lib/sd_340.php";

define("HDC1000_ADDR",                0x40);

define("HDC1000_TEMP",                0x00);
define("HDC1000_HUMI",                0x01);
define("HDC1000_CONFIG",            0x02);

define("HDC1000_SERID_1",            0xFB);
define("HDC1000_SERID_2",            0xFC);
define("HDC1000_SERID_3",            0xFD);
define("HDC1000_MFID",                0xFE);
define("HDC1000_DEVID",                0xFF);

define("HDC1000_RST",                0x80);
define("HDC1000_HEAT_ON",            0x20);
define("HDC1000_HEAT_OFF",            0x00);
define("HDC1000_BOTH_TEMP_HUMI",    0x10);
define("HDC1000_SINGLE_MEASUR",        0x00);
define("HDC1000_TEMP_HUMI_14BIT",    0x00);
define("HDC1000_TEMP_11BIT",        0x40);
define("HDC1000_HUMI_11BIT",        0x01);
define("HDC1000_HUMI_8BIT",            0x02);

$pid = 0;

function i2c_HDC1000_setup($i2c_id)
{
    global $pid ;
    
    $sensor_addr = sprintf("%02x", HDC1000_ADDR << 1);
    
    $pid = pid_open("/mmap/i2c$i2c_id");
    pid_ioctl($pid, "req reset");
    pid_ioctl($pid, "set saddr $sensor_addr");
    pid_ioctl($pid, "set mode sm");
    pid_ioctl($pid, "set role master");
}

// Generic I2C read registers (two bytes, LSB first)
function HDC1000_read16($addr_reg)
{
    global $pid ;
    
    $data_lsb = 0x00;
    $data_msb = 0x00;
    
    pid_ioctl($pid, "req reset");
    pid_ioctl($pid, "req write wait");
    // register to read
    pid_write($pid, $addr_reg, 1); 
    
    pid_ioctl($pid, "req stop"); // stop writing data
    usleep(20000);    
    pid_ioctl($pid, "req read 2"); // request to read 2 bytes
    while(pid_ioctl($pid, "get rxlen") < 2); // check received data
    
    pid_read($pid, $data_msb, 1); // read buffer
    pid_read($pid, $data_lsb, 1); // read buffer
            
    return ($data_lsb | ($data_msb << 8));
}

// Generic I2C write $data to registers (two bytes, LSB first)
function HDC1000_write16($addr_reg, $data)
{        
    global $pid ;
    
    $data_lsb = $data & 0xff;
    $data_msb = $data >> 8;
    
    pid_ioctl($pid, "req reset");
    pid_ioctl($pid, "req write wait");
    //register to read
    pid_write($pid, $addr_reg, 1); 
    pid_write($pid, $data_lsb, 1); 
    pid_write($pid, $data_msb, 1); 
    while(pid_ioctl($pid, "get txlen")); // check received data
    
    pid_ioctl($pid, "req stop"); // stop writing data
}

function HDC1000_read_temperature()
{    
    $temp = HDC1000_read16(HDC1000_TEMP);

    return $temp/65536.0*165.0-40.0;
}

function HDC1000_read_humidity()
{    
    $humi = HDC1000_read16(HDC1000_HUMI);
         
    return $humi/65536.0*100.0;
}

?>

HTS221 Library (vd_hts221.php)

PHP
HTS221 Sensor Library
<?php

include_once "/lib/sd_340.php";

define("HTS221_ADDR",        0x5F);

//Define a few of the registers that we will be accessing on the HTS221
define("WHO_AM_I",           0x0F);
define("WHO_AM_I_RETURN",    0xBC); //This read-only register contains the device identifier, set to BCh

define("AVERAGE_REG",        0x10); // To configure humidity/temperature average.
define("AVERAGE_DEFAULT",    0x1B);

define("CTRL_REG1",          0x20);
define("POWER_UP",           0x80);
define("BDU_SET",            0x4);
define("ODR0_SET",           0x1);   // setting sensor reading period 1Hz

define("CTRL_REG2",          0x21);
define("CTRL_REG3",          0x22);
define("REG_DEFAULT",        0x00);

define("STATUS_REG",         0x27);
define("TEMPERATURE_READY",  0x1);
define("HUMIDITY_READY",     0x2);

define("HUMIDITY_L_REG",     0x28);
define("HUMIDITY_H_REG",     0x29);
define("TEMP_L_REG",         0x2A);
define("TEMP_H_REG",         0x2B);

define("CALIB_START",        0x30);
define("CALIB_END",           0x3F);

/*
define("CALIB_T0_DEGC_X8",   0x32);
define("CALIB_T1_DEGC_X8",   0x33);
define("CALIB_T1_T0_MSB",    0x35);
define("CALIB$T0_OUT_L",     0x3C);
define("CALIB$T0_OUT_H",     0x3D);
define("CALIB$T1_OUT_L",     0x3E);
define("CALIB$T1_OUT_H",     0x3F);
 */

$h0_rH = 0;
$h1_rH = 0;
$T0_degC = 0;
$T1_degC = 0;
$H0_T0 = 0;
$H1_T0 = 0;
$T0_OUT = 0;
$T1_OUT = 0;

$pid = 0;

function twobyte2singedint($twobyte)
{
    if($twobyte & 0x8000)
    {
        $twobyte = ($twobyte & 0x7fff) - 0x8000;
    }
    
    return $twobyte;
}

function i2c_HTS221_setup($i2c_id)
{
    global $pid ;
    
    $sensor_addr = sprintf("%02x", HTS221_ADDR << 1);
    
    $pid = pid_open("/mmap/i2c$i2c_id");
    pid_ioctl($pid, "req reset");
    pid_ioctl($pid, "set saddr $sensor_addr");
    pid_ioctl($pid, "set mode sm");
    pid_ioctl($pid, "set role master");
    //pid_close($pid);
}

// Generic I2C read register (single byte)
function HTS221_read8($addr_reg)
{
    global $pid ;
    //$pid = pid_open("/mmap/i2c0"); // open I2C 0
    pid_ioctl($pid, "req reset");
    //pid_write($pid, "\x30\x00");
    pid_ioctl($pid, "req write wait");
    // register to read
    pid_write($pid, $addr_reg, 1); 
    //while(pid_ioctl($pid, "get txlen")); // check transmitted data
    
    pid_ioctl($pid, "req stop"); // stop writing data
    
    $data = 0;
    pid_ioctl($pid, "req read 1"); // request to read 1 bytes
    while(pid_ioctl($pid, "get rxlen") < 1) // check received data
    ;
    pid_read($pid, $data, 1); // read buffer
    //pid_close($pid);
    
    return $data;
}

// Generic I2C write $data to register (single byte)
function HTS221_write8($addr_reg, $data)
{
    global $pid ;
    //$pid = pid_open("/mmap/i2c0"); // open I2C 0
    pid_ioctl($pid, "req reset");
    //pid_write($pid, "\x40\x00");
    pid_ioctl($pid, "req write wait");
    //register to read
    pid_write($pid, $addr_reg, 1); 
    pid_write($pid, $data, 1); 
    while(pid_ioctl($pid, "get txlen")); // check transmitted data
    
    pid_ioctl($pid, "req stop"); // stop writing data
    //pid_close($pid);
}

function HTS221_activate()
{
    $data = HTS221_read8(CTRL_REG1);
    $data |= POWER_UP;
    $data |= ODR0_SET;
    HTS221_write8(CTRL_REG1, $data);
    
    return true;
}

function HTS221_store_calibration()
{
    global $h0_rH;
    global $h1_rH;
    global $T0_degC;
    global $T1_degC;
    global $H0_T0;
    global $H1_T0;
    global $T0_OUT;
    global $T1_OUT;    
    
    for ($reg=CALIB_START; $reg<=CALIB_END; $reg++) 
    {
        if (($reg!=CALIB_START+8) && ($reg!=CALIB_START+9) && ($reg!=CALIB_START+4)) 
        {
            
            $data = HTS221_read8($reg);
            
            switch ($reg) 
            {
                case CALIB_START:
                    $h0_rH = $data;
                    break;
                case CALIB_START+1:
                    $h1_rH = $data;
                    break;
                case CALIB_START+2:
                    $T0_degC = $data;
                    break;
                case CALIB_START+3:
                    $T1_degC = $data;
                    break;
                    
                case CALIB_START+5:
                    $tmp = $T0_degC;
                    $T0_degC = ($data&0x3)<<8;
                    $T0_degC |= $tmp;
                    
                    $tmp = $T1_degC;
                    $T1_degC = (($data&0xC)>>2)<<8;
                    $T1_degC |= $tmp;
                    break;
                case CALIB_START+6:
                    $H0_T0 = $data;
                    break;
                case CALIB_START+7:
                    $H0_T0 |= $data<<8;
                    break;
                case CALIB_START+0xA:
                    $H1_T0 = $data;
                    break;
                case CALIB_START+0xB:
                    $H1_T0 |= $data <<8;
                    break;
                case CALIB_START+0xC:
                    $T0_OUT = $data;
                    break;
                case CALIB_START+0xD:
                    $T0_OUT |= $data << 8;
                    break;
                case CALIB_START+0xE:
                    $T1_OUT = $data;
                    break;
                case CALIB_START+0xF:
                    $T1_OUT |= $data << 8;
                    break;
                    
                    
                case CALIB_START+8:
                case CALIB_START+9:
                case CALIB_START+4:
                //DO NOTHING
                break;
                
                // to cover any possible error
                default:
                    return false;
            } /* switch */
        } /* if */
    }  /* for */
    
    $T0_OUT = twobyte2singedint($T0_OUT);
    $T1_OUT = twobyte2singedint($T1_OUT);
    $H0_T0 = twobyte2singedint($H0_T0);
    $H1_T0 = twobyte2singedint($H1_T0);
    
    return true;
}

function HTS221_init()
{
    $data = HTS221_read8(WHO_AM_I);
    
    if ($data == WHO_AM_I_RETURN)
    {
        if (HTS221_activate())
        {
            HTS221_store_calibration();
            return true;
        }
    }
    
    return false;
}

function HTS221_read_temperature()
{    
    global $h0_rH;
    global $h1_rH;
    global $T0_degC;
    global $T1_degC;
    global $H0_T0;
    global $H1_T0;
    global $T0_OUT;
    global $T1_OUT;    
    
    $data   = 0;
    $t_out = 0;
    $t_temp  = 0.0;
    $deg     = 0.0;
    
    $data = HTS221_read8( STATUS_REG);
    
    if ($data & TEMPERATURE_READY) 
    {
        
        $data= HTS221_read8( TEMP_H_REG);
        $t_out = $data  << 8; // MSB
        $data = HTS221_read8( TEMP_L_REG);
        $t_out |= $data;      // LSB
        
        $t_out = twobyte2singedint($t_out);
        
        // Decode Temperature
        $deg = (float)($T1_degC - $T0_degC); 
        
        // Calculate Temperature in decimal of grade centigrades i.e. 15.0 = 150.
        $t_temp = ($t_out - $T0_OUT) * $deg / ($T1_OUT - $T0_OUT);
        $temperature = $t_temp + $T0_degC;   // provide signed celsius measurement unit
        // remove x8 multiple
        $temperature /= 8;
    }
    else
        $temperature = false;
    
    return $temperature;
}

function HTS221_read_humidity()
{    
    global $h0_rH;
    global $h1_rH;
    global $T0_degC;
    global $T1_degC;
    global $H0_T0;
    global $H1_T0;
    global $T0_OUT;
    global $T1_OUT;
    
    $data   = 0;
    $h_out = 0;
    $h_temp  = 0.0;
    $hum     = 0.0;
    
    $data = HTS221_read8( STATUS_REG);
    
    if ($data & HUMIDITY_READY) 
    {
        $data = HTS221_read8( HUMIDITY_H_REG);
        $h_out = $data << 8;  // MSB
        $data = HTS221_read8( HUMIDITY_L_REG);
        $h_out |= $data;      // LSB
        
        $h_out = twobyte2singedint($h_out);
        
        // Decode Humidity
        $hum = (($h1_rH) - ($h0_rH))/2.0;  // remove x2 multiple
        
        // Calculate humidity in decimal of grade centigrades i.e. 15.0 = 150.
        $h_temp = (($h_out - $H0_T0) * $hum) / ($H1_T0 - $H0_T0);
        $hum    = ($h0_rH) / 2.0; // remove x2 multiple
        $humidity = (($hum + $h_temp)); // provide signed % measurement unit
    }
    else
        $humidity = false;
    return $humidity;
}

?>

Credits

phpoc_man

phpoc_man

62 projects • 406 followers

Comments