IR Repeater

IR Repeater

Postby Khanh » Thu Jul 21, 2016 7:16 pm

IR Repeater

Introduction

Internet IR remote controller is great solution to control your device when you are far from your house or office. However, when you are in your home or your office, you may not want to open your phone or computer. You just want to take the normal IR remote controller and control your devices. In this case, Internet IR remote controller seems to not so convenient as normal IR controller. Nonetheless, other situations come up:
    - There some obstacles between you and your device (in my case, I put my air-conditioner to noise-absorbed box)
    - The distance between your desk and your device is farther than IR range.

The solution for these cases is IR repeater which extends the range of remote-controller and overcome obstacles.

The implementation is quite simple if you already read my previous articles about IR. You don’t need to analyze the signal from remote-controller. You also don’t need to know devices address and command set. You only need to captures pulse chains from IR receiver, send out this chain to IR emitter, so it works for all devices.

Thing we need:

    - One PHPoC Blue
    - One IR receiver
    - One IR emitter
    - One Resistor 1kΩ
    - Grove expansion board (optional)

The wiring

wiring.PNG
wiring.PNG (65.44 KiB) Viewed 4084 times


This code shows the implementation of IR repeater using PHPoC.
<task0.php>
Code: Select all

<?php
 
if(_SERVER("REQUEST_METHOD"))
    exit; // avoid php execution via http request
 
include_once 
"/lib/sd_340.php";
include_once "/lib/vd_nec_infrared.php";

$rbuf = "";
$unit = 562.5 / 5;//µs
$repc = 80; 
$lower_bound 
= 1000; 
$upper_bound 
= 14000;

while(
1)
{
        
    
    
//IR Repeater Function
    infrared_capture_start($unit, $repc);
    usleep(500000);    
    infrared_recv_stop
();
    
    if
(infrared_available($lower_bound, $upper_bound))
    {
        echo "\r\n";
        $count_buf = int2bin(1, 2);    // first value is dummy.
        $cnt_buf_len = 1;
        for($i = 0; $i <= $repc; $i++)
        {
            //get width of pulses
            $count = infrared_get_raw_count($i);
            if($count)
            {
                $count_buf .= int2bin($count, 2);  
                $cnt_buf_len
++;
                echo "$count, ";
            }
        }
        infrared_emit($count_buf, $cnt_buf_len, $unit);    
    
}        
}
 
?>


As you can see on above code, no device address, no command and bit pattern are required. Therefore, it works for all kinds of devices which use NEC or variation of NEC protocol (for other protocols, you may need to change $unit, $repc, $lower_bound and $upper_bound).

Taking advantage of network function on PHPoC, I integrated the Internet IR remote control function into IR repeating function, so you can use both internet IR controller and IR repeater at the same time with the same hardware (Note that you need to insert USB wireless LAN dongle). To simplify, I only add one power button to turn on/off. For other buttons, please visit here: viewtopic.php?f=42&t=184

Furthermore, I add a temperature sensor to monitor temperature (TH02 temp&humi sensor)
Source code for this:
<task0.php>
Code: Select all

<?php
 
if(_SERVER("REQUEST_METHOD"))
    exit; // avoid php execution via http request
 
include_once 
"/lib/sd_340.php";
include_once "/lib/sn_tcp_ws.php";
include_once "/lib/vd_nec_infrared.php";
include_once "/lib/vd_th02.php";

define("AIRCON_ADDRESS",   0x01ff);

$rbuf = "";
$unit = 562.5 / 5;//µs
$repc = 80; 
$lower_bound 
= 1000; 
$upper_bound 
= 14000;

i2c_TH02_setup(0);
ws_setup(0, "phpoc_infrared_relay", "csv.phpoc");

$max_samples = 15;
$sample_count = 0;

$temp_str = "";

while(
1)
{
        
    if
(ws_state(0) == TCP_CONNECTED)
    {
        //Internet IR controller Function
        $rlen = ws_read_line(0, $rbuf);

        if($rlen)
        {
            $cmd = (int)$rbuf;
            $data = (AIRCON_ADDRESS << 16) | ($cmd <<8) | ((~$cmd)&0xff);
            nec_infrared_send($data, 32);            
        
}
        
        
// Temperature Monitoring
        $temp = TH02_read_temperature();
        $temp = sprintf("%.01f", $temp);
        if($sample_count == 0)    
        
{
            $temp_str = $temp;
        }
        else
            $temp_str 
.= ",$temp" ;
        
        $sample_count
++;
        
        if
($sample_count > $max_samples)
        {
            $pos = strpos($temp_str, ",");
            
            if
( is_int($pos) )
                $temp_str = substr($temp_str, $pos+1);
            
            $sample_count 
= $max_samples;
        }
        
        $wbuf 
= "[$temp_str]";
        
        ws_write
(0, $wbuf);
        
    
}    
    
    
//IR Repeater Function
    infrared_capture_start($unit, $repc);
    usleep(500000);    
    infrared_recv_stop
();
    
    if
(infrared_available($lower_bound, $upper_bound))
    {
        echo "\r\n";
        $count_buf = int2bin(1, 2);    // first value is dummy.
        $cnt_buf_len = 1;
        for($i = 0; $i <= $repc; $i++)
        {
            //get width of pulses
            $count = infrared_get_raw_count($i);
            if($count)
            {
                $count_buf .= int2bin($count, 2);  
                $cnt_buf_len
++;
                echo "$count, ";
            }
        }
        infrared_emit($count_buf, $cnt_buf_len, $unit);    
    
}        
}
 
?>


Because we have web user interface, we need to add index.php file source as follow
<index.php>
Code: Select all
<?php   
   // To get the command set, please visit http://www.phpoc.com/forum/viewtopic.php?f=42&t=183
   define("CMD_POWER",   57);
?>
<!DOCTYPE html>
<html>
<head>
<title>PHPoC Infrared Control</title>
<meta name="viewport" content="width=device-width, initial-scale=0.7">
<style type="text/css">
body { text-align: center; position: relative;}
#view {
   font-weight: bold; font-family : verdana, Helvetica, Arial, verdana, sans-serif, gulim; font-size:14pt; padding:10px;
   background-color: rgb(6, 38, 111);
   color: white;
}
#temp {
   font-weight: bold; font-family : verdana, Helvetica, Arial, verdana, sans-serif, gulim; font-size:25pt;
   margin-bottom: 5px;
}
#blink_ {
   color: rgb(0,153,153);
}
#graph {
    border: 1px solid #000;
   position: relative;
   margin-bottom: 5px;
   display: none;
}
#remote_con {
    margin-right: auto;
    margin-left: auto;
   width:100px; height:110px;
    position: relative;
    margin-bottom: 10px;
}
.button {
   position: absolute;
   left: 0px; top: 0px;
   width:100px; height:100px;
   background: url(inactive.png) no-repeat;
   background-size: contain;
}

</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script type="text/javascript">
var CMD_POWER =   57;

var cmd = 0;
var canvas_width = 400;
var canvas_height = 240;
var padding = 35;
var pivot_x = padding;
var pivot_y = canvas_height - padding;
var ws = null;
var cvs = null, ctx = null;
var step_x = 30;
var step_y = 30;
var max_samples = 15;

function init()
{
   var view = document.querySelector("#view");
    view.addEventListener("click", option_onclick);
   //Temperature part
   cvs = document.getElementById("graph");
   cvs.width = canvas_width;
   cvs.height = canvas_height; 
   ctx = cvs.getContext("2d");
   
   ctx.translate(pivot_x, pivot_y);
   //ctx.rotate(Math.PI *3 / 2);
   
   draw_all_text();
   draw_baseline();
   
   //Control part
   var remote_con = document.querySelector("#remote_con");
    remote_con.addEventListener("touchstart", mouse_down);
    remote_con.addEventListener("touchend", mouse_up);
    remote_con.addEventListener("touchcancel", mouse_up);
    remote_con.addEventListener("mousedown", mouse_down);
    remote_con.addEventListener("mouseup", mouse_up);
    remote_con.addEventListener("mouseout", mouse_up);            
}

function ws_onmessage(e_msg)
{
    console.log(e_msg.data);   
   var arr = JSON.parse(e_msg.data);
   update_view(arr);
}

function ws_onopen()
{
   document.getElementById("ws_state").innerHTML = "OPEN";
   document.getElementById("wc_conn").innerHTML = "Disconnect";
   document.getElementById(CMD_POWER).style.backgroundImage = "url('unpressed.png')";
}
function ws_onclose()
{
   document.getElementById("ws_state").innerHTML = "CLOSED";
   document.getElementById("wc_conn").innerHTML = "Connect";
   document.getElementById(CMD_POWER).style.backgroundImage = "url('inactive.png')";
   document.getElementById("blink_").innerHTML = "null";
   ctx.clearRect(-pivot_x, -pivot_y, canvas_width, canvas_height);   
   draw_all_text();
   draw_baseline();
   
   console.log("socket was closed");
      
   ws.onopen = null;
   ws.onclose = null;
   // ws.onmessage = null;
   ws = null;
}
function wc_onclick()
{
   if(ws == null)
   {
      ws = new WebSocket("ws://<?echo _SERVER('HTTP_HOST')?>/phpoc_infrared_relay", "csv.phpoc");
      document.getElementById("ws_state").innerHTML = "CONNECTING";
      
      ws.onopen = ws_onopen;
      ws.onclose = ws_onclose;
      ws.onmessage = ws_onmessage;
   }
   else
      ws.close();
}
function option_onclick(event)
{
   if (event.target !== event.currentTarget)
   {
      var id = event.target.value;
      if(event.target.checked)
         $("#"+id).show();
      else
         $("#"+id).hide();
    }
    //event.stopPropagation();   
    //event.preventDefault();   
}
function mouse_down(event)
{
   if (event.target !== event.currentTarget)
   {
      var id = event.target.id;
      
      if(ws != null)
         event.target.style.backgroundImage = "url('pressed.png')";
      
      console.log(id);
      send_command(id);
    }
    event.stopPropagation();   
    event.preventDefault();   
}

function mouse_up(event)
{
   if (event.target !== event.currentTarget)
   {
      if(ws != null)
         event.target.style.backgroundImage = "url('unpressed.png')";
    }
    event.stopPropagation();   
    event.preventDefault();   
}

function send_command(cmd)
{   
   if(ws != null)
      if(ws.readyState == 1)
         ws.send(cmd + "\r\n");   
}

//Drawing
function draw_point(x, y, radius , color )
{
   ctx.fillStyle = color;
   ctx.beginPath();
   ctx.arc(x, y, radius, 0, 2*Math.PI);
   //ctx.closePath();      
   ctx.fill();
}
function draw_all_text()
{
   var y = 0;
   var x = -25;
   ctx.font = "12px calibri";
   ctx.fillStyle = "gray";
   ctx.textBaseline="middle";
   
   ctx.fillText("  0", x, y); y -= step_y;
   ctx.fillText(" 10", x, y); y -= step_y;
   ctx.fillText(" 20", x, y); y -= step_y;
   ctx.fillText(" 30", x, y); y -= step_y;
   ctx.fillText(" 40", x, y); y -= step_y;
   ctx.fillText(" 50", x, y); y -= step_y;
   
   /* x axis labels */
   ctx.fillText("Time (Sec.)", canvas_width - 2*padding - 30, 15);
   
   /* y axis labels */
   ctx.fillText("Temps ('c)", -20, - 5*step_y - 20);
}
function draw_baseline()
{   
   ctx.lineWidth = 0.5;     
    ctx.strokeStyle = "gray";
   
    for(var i = 0; i <= 5; i++)
   {
      ctx.beginPath();
      ctx.moveTo(-5, -(i*step_y));
      ctx.lineTo(canvas_width - 2*padding, -(i*step_y));
      ctx.stroke();
   }   
   ctx.lineWidth = 3;
   ctx.strokeStyle = "#707070";
   // x axis   
   ctx.beginPath();
   ctx.moveTo(0, 0);
   ctx.lineTo(canvas_width - 2*padding + 10, 0);
   ctx.stroke();
   // y axis   
   ctx.beginPath();
   ctx.moveTo(0, 0);
   ctx.lineTo(0, - 5*step_y - 10);
   ctx.stroke();
}

function draw_scratch(data)
{   
   var x = canvas_width -2*padding;
   step_x = x / (max_samples-1);
   ctx.lineWidth = 3;     
    ctx.strokeStyle = "#20B2AA";
   
   ctx.beginPath();
   for(var i = data.length - 1; i >= 0; i--)
   {
      var y = - data[i] *step_y/10;
      ctx.lineTo(x, y);
      x -= step_x;      
   }
   ctx.stroke();
   x = canvas_width -2*padding;
   for(var i = data.length - 1; i >= 0; i--)
   {
      var y = - data[i] *step_y/10;
      draw_point(x, y, 3, "#20B2AA");
      x -= step_x;      
   }
   //Latest Temperature
   x = canvas_width -2*padding;
   y = - data[data.length - 1] *step_y/10;
   draw_point(x, y, 4, 'red');
   ctx.fillText(" " + data[data.length - 1] + "'C", x + 5, y);
   
   document.getElementById("blink_").innerHTML = data[data.length - 1];
   
}

function update_view(data)
{
   ctx.clearRect(-pivot_x, -pivot_y, canvas_width, canvas_height);   
   draw_all_text();
   draw_baseline();
   draw_scratch(data);
}
function blinker() {
    $('#blink_').fadeOut(300);
    $('#blink_').fadeIn(1200);
}

setInterval(blinker, 1500);
   
window.onload = init;
</script>
</head>
<body>
<div id="view">
   <input type="checkbox" name="view_option" value="temp" checked> Temprature
   <input type="checkbox" name="view_option" value="graph"> Graph
   <input type="checkbox" name="view_option" value="remote_con" checked> Remote-Con
</div>
<p id="temp"> Temp: <span id="blink_">null</span> &deg;C</p>

<canvas id="graph"></canvas><br>
<div id="remote_con">
    <div id="<?php echo CMD_POWER?>" class="button"></div>
</div>
<p>
WebSocket : <span id="ws_state">null</span><br>
</p>
<button id="wc_conn" type="button" onclick="wc_onclick();">Connect</button>
</body>
</html>


User interface will be like this

ui.PNG
ui.PNG (37.36 KiB) Viewed 4084 times


You need to add libraries for:

Khanh
 
Posts: 69
Joined: Fri Mar 11, 2016 10:57 am

Return to Project

Who is online

Users browsing this forum: No registered users and 2 guests

cron