HTML, ajax, and php proxy Variable Calls work, Function Calls don't [Solved]

I’ve searched and I’ve read the posts and I’m close, as I have variable calls working but having difficulty getting a function call to work. I get the feeling it’s just some simple syntax I have wrong but do not have the expertise to figure it out and now basically rereading existing posts and going around in circles.
It was all working with direct calls, but using the PHP to hide and insert access token fails on function calls.

Any assistance would be appreciated.

Working Html for variable call:

        function getVariable(variable, callback) {
          var url = baseURL + "?method=" + variable + "&device=" + coreID;
          $.ajax({
            url: url,
            dataType: "json"
          }).success(function(obj) {
            console.log(obj);
            (obj.coreInfo.deviceID && obj.coreInfo.deviceID == coreID) ? onMethodSuccess() : onMethodFailure ((obj.error)?obj.error:"");
            callback(obj.result);
          }).fail(function(obj) {
            onMethodFailure();
          });
        }

Non working Html for function call:

        function doMethod(vmethod, data) {
//          var url = baseURL + coreID + "/" + vmethod;
          var url = baseURL + "?method=" + vmethod + "&device=" + coreID ;
          $.ajax({
            type: "POST",
            url: url,
            data: {
              args: data
            },
            dataType: "json"
          }).success(function(obj) {
            console.log(obj);
            (obj.return_value && obj.return_value == 200) ? onMethodSuccess() : onMethodFailure((obj.error)?obj.error:"");
          }).fail(function(obj) {
            onMethodFailure();
          });
        }

Old html working without php:

// The base level run method command  -----------------------------function - doMethod
        function doMethod(method, data) {
          var url = baseURL + coreID + "/" + method;
          $.ajax({
            type: "POST",
            url: url,
            data: {
              access_token: accessToken,
              args: data
            },
            dataType: "json"
          }).success(function(obj) {
            console.log(obj);
            (obj.return_value && obj.return_value == 200) ? onMethodSuccess() : onMethodFailure((obj.error)?obj.error:"");
          }).fail(function(obj) {
            onMethodFailure();
          });
        }

PHP file in root directory:

<?php
$device = $_REQUEST["device"];
$method = $_REQUEST["method"];
if(!$device||!$method) die("device or method param missing\n");
// add access token
$_REQUEST["access_token"] = "123456789";
// create params
$params = http_build_query($_REQUEST);

// make request
$url = "https://api.spark.io/v1/devices/" . $device . "/" . $method . "?" . $params;
$response = file_get_contents($url);
echo $response; 
?>

The file_get_contents() PHP function you’re using does an HTTP GET by default. You’ll need to create and pass a “context” to do HTTP POST in the file_get_contents() function.

This is an adaptation of example #4 from http://php.net/file_get_contents and your code above. I haven’t tested it, but it should get you close if it doesn’t work. It may need a "Content-length=".strlen($params)."\r\n" added to the context headers as well.

<?php
// Create a stream
$opts = array(
  'http'=>array(
    'method'=>"POST",
    'header'=>"Authorization: Bearer ".$_REQUEST['access_token']."\r\n"
  )
);

$context = stream_context_create($opts);

$url = "https://api.spark.io/v1/devices/" . $device . "/" . $method . "?" . $params;
$response = file_get_contents($url, false, $context);
echo $response; 
?>

Also, in your “Non working Html for function call” example, you are not passing the access_token variable, but your PHP script expects it, so make sure that gets taken care of as well.

Thanks ever so much for the reply -
This has been very frustrating.
Been trying to learn and troubleshoot this but I'm still a little lost -

1 - I don't see where are we adding the function data in the array? $method is the function
2 - It was my understanding that the php script was Adding the access-token so we wouldn't need to have it viewable in the html.

Have been working with example from this thread

From looking at an online html debugger console, I can see the array is never being sent, just the main line with function name and device ID

Oops! The script I posted was to replace everything below the // Make request part. And upon re-reading your code, it looks like you are specifying the access token in PHP, so disregard that comment. :wink:

With some playing I’m able to get a return value of -1, but something is still missing

id: "23575..."
last_app:""
connected:true
return_value: -1

Can you post your new PHP code (minus the access token)?

Sure - and thanks for your continued help, Garret :slight_smile:

This is what I put together from your posts that had no response:

<?php
$device = $_REQUEST["device"];
$method = $_REQUEST["method"];
if(!$device||!$method) die("device or method param missing\n");

// add access token
$_REQUEST["access_token"] = "1234";

// create params
$params = http_build_query($_REQUEST);

// Create a stream
$opts = array(
  'http'=>array(
    'method'=>"POST",
    'header'=>"Authorization: Bearer ".$_REQUEST['access_token']."\r\n"
  )
);

$context = stream_context_create($opts);

$url = "https://api.spark.io/v1/devices/" . $device . "/" . $method . "?" . $params;
$response = file_get_contents($url, false, $context);
echo $response; 
?>

And here I changed $params to $opts in $url= that got return -1

<?php
$device = $_REQUEST["device"];
$method = $_REQUEST["method"];
if(!$device||!$method) die("device or method param missing\n");

// add access token
$_REQUEST["access_token"] = "1234";

// create params
$params = http_build_query($_REQUEST);

// Create a stream
$opts = array(
  'http'=>array(
    'method'=>"POST",
    'header'=>"Authorization: Bearer ".$_REQUEST['access_token']."\r\n"
  )
);

$context = stream_context_create($opts);

$url = "https://api.spark.io/v1/devices/" . $device . "/" . $method . "?" . $opts;
$response = file_get_contents($url, false, $context);
echo $response; 
?>

For grins I try adding “echo $params” to the end of the script and it shows

{
"id": "3e002a000547343337373737",
  "last_app": "",
  "connected": true,
  "return_value": -1
}method=multiwig&device=3e002a000547343337373737&args=HTRLY%2C000%2C1&s_fid=5004CA16CC809392-18763FA3C77EAD71&wordpress_test_cookie=WP+Cookie+check&access_token=1234

After much experimentation, I’m thinking this should work - added in the “args” but still returns -1. I’m sure I’m close on this.

<?php
$device = $_REQUEST["device"];
$method = $_REQUEST["method"];
if(!$device||!$method) die("device or method param missing\n");

// add access token
$_REQUEST["access_token"] = "1234";

// create params
$params = http_build_query($_REQUEST);
$args = $_REQUEST["args"];

// make request
// Create a stream
$opts = array(   
  'http'=>array( 
    'method'=>"POST",
    'header'=>"Authorization: Bearer ".$_REQUEST['access_token'],
    'args'=>$args."\r\n"
    )
);

$context = stream_context_create($opts);

$url = "https://api.spark.io/v1/devices/" . $device . "/" . $method . "?";
$response = file_get_contents($url, false, $context);
echo $response;
//echo $token;
//echo " params: ", $params;
//print_r($opts);
//print($context);
?>

What does your function look like on your device (Photon/Electron/Core/etc)?

I changed the return values to get a better ID on the return values. We now get a return value of -99 ( the last in the series)

With debugging on I can see we get no value for the args, but the access token is obviously sending otherwise we wouldn’t get the reply. Changing the access token proved that.

Particle.function("multiwig", multiwidget);
/*/

Command string format is:  function value switch 0/1 or parameter
                              xxxxxnnnnnn
 for example: PIRPC0051    (Pir PulseCount 5 - ON)
              DREADA100    (digitalRead pin A1)
              DWRITD201    (digitalWrite pin D2 - High/On)
              AWRITA201    (analogWrite pin2 - 255)


Functions:

PIRPC  PIR Pulsecount and toggle
PIRWT  PIR Walk-Test LED Switch (on/off)
DWRIT  digitalWrite
DREAD  digitalRead
AWRIT  analogWrite
AREAD  analogRead
HTEMP  High Temp setting and on/off
HTRLY  High Temp Relay Override on/off
OTEMP  Over Temp setting and on/off
OTRLY  Over Temp Relay Override on/off
NOTFY  PushingBox Notification on/off 
RELAY  Notofications Only - No relay response
TIMER  Timer reminder setting and on/off
NOLED  Stealth mode on/off
SLEEP  Shuts off all processing
/*/


int multiwidget(String wigString)
{
 
//find command in string (first 5 characters)
  String wigCommand = String (wigString.substring(0,5)) ;
 
//find value in string (next 3 characters)
  String wigValueS = (wigString.substring(5,8));
                
// Check command start letter for D or A to prevent converting first character of value to a number
  if (wigCommand.charAt(0) != 'D' && wigCommand.charAt(0) != 'A') 
      if(DEBUG){Serial.print(">>Command Not D or A:");}
     int wigValueI = wigValueS.toInt();

//find switch value in string and convert ascii to integer

    String wigSwitchS = (wigString.substring(8,10));
    wigSwitch = wigSwitchS.toInt();


    if(DEBUG){Serial.print(">wigSwitch:");
            Serial.print(wigSwitch);
        Serial.print(">wigSwitchS:");
            Serial.println(wigSwitchS);
        Serial.print(">wigCommand:");
            Serial.println(wigCommand);
        Serial.print(">wigValueS:");
            Serial.println(wigValueS);
        Serial.print(">wigString:");
            Serial.println(wigString);
                }



// Digital Write    -------------------------------------------------------------Digital Write DWRIT 
   if (wigCommand == "DWRIT")   // Digital Write
   {
           //convert ascii to integer
    int pinNumber = wigValueS.charAt(1) - '0';
    //Sanity check to see if the pin numbers are within limits
    if (pinNumber< 0 || pinNumber >7) return -01;

    if(wigValueS.startsWith("D"))
    {
        pinMode(pinNumber, OUTPUT);
        digitalWrite(pinNumber, wigSwitch);
        return 1;
    }
    else if(wigValueS.startsWith("A"))
    {
        pinMode(pinNumber+10, OUTPUT);
        digitalWrite(pinNumber+10, wigSwitch);
        return 1;
    }
    
   }
    else   

// Digital Read     -------------------------------------------------------------Digital Read DREAD
   if (wigCommand == "DREAD")  
    {
             //convert ascii to integer
    int pinNumber = wigValueS.charAt(1) - '0';
    //Sanity check to see if the pin numbers are within limits
    if (pinNumber< 0 || pinNumber >7) return -02;

    if(wigValueS.startsWith("D"))
    {
        pinMode(pinNumber, INPUT_PULLDOWN);
        return digitalRead(pinNumber);
    }
    else if (wigValueS.startsWith("A"))
    {
        pinMode(pinNumber+10, INPUT_PULLDOWN);
        return digitalRead(pinNumber+10);
    }
    
   }
    
    else   
    
// Analog Read      -------------------------------------------------------------Analog Read AREAD
   if (wigCommand == "AREAD")
     {  
    
     //convert ascii to integer
    int pinNumber = wigValueS.charAt(1) - '0';
   
   if(DEBUG){ 
       Serial.println("AREAD:");
       Serial.print(">pinNumber:");
        Serial.print(pinNumber);
   }

    //Sanity check to see if the pin numbers are within limits
    if (pinNumber< 0 || pinNumber >7) return -03;

    if(wigValueS.startsWith("D"))
    {
        pinMode(pinNumber, INPUT);
        return analogRead(pinNumber);
    }
    else if (wigValueS.startsWith("A"))
    {
        pinMode(pinNumber+10, INPUT);
        return analogRead(pinNumber+10);
    }        
        
     }
    else      
// Anlog Write      -------------------------------------------------------------Analog Write AWRIT
    if (wigCommand == "AWRIT")
      {
           //Pin and Value (0 to 255)
   
    //convert ascii to integer
    int pinNumber = wigValueS.charAt(1) - '0';
    //Sanity check to see if the pin numbers are within limits
    if (pinNumber< 0 || pinNumber >7) return -04;

//    String aValueS = wigValueS.substring(3);

if(DEBUG){ 
       Serial.println("AWRIT:");
       Serial.print(">pinNumber:");
        Serial.print(pinNumber);
       Serial.print(">wigSwitch:");
        Serial.print(wigSwitch);

   }



    if(wigValueS.startsWith("D"))
    {
        pinMode(pinNumber, OUTPUT);
        analogWrite(pinNumber, wigSwitch);
        return 1;
    }
    else if(wigValueS.startsWith("A"))
    {
        pinMode(pinNumber+10, OUTPUT);
        analogWrite(pinNumber+10, wigSwitch);
        return 1;
    }          

      }
    else   
    
// PIR Pulse Count and toggle ----------------------------------------------------PIR  PIRPC
    if (wigCommand == "PIRPC")   
    {
        if(DEBUG){Serial.print(">PIRPC:");}
       if (wigValueI >= 0 && wigValueI <= 9) 
        { 
            pirPulseCount = wigValueI;
            pirEnable = wigSwitch;
            updateMultiSwitch();
            return 200;
        }
    }    
    else   

// PIR WAlk-test LED toggle ------------------------------------------------------PIR Walk Test  PIRWT
    if (wigCommand == "PIRWT")   
     {  
        if(DEBUG){Serial.print(">PIRPWT");}
        pirLedEnable = wigSwitch;
        updateMultiSwitch();        
         return 200;       
//        if (wigSwitch == '1') 
//            int pirLED = HIGH;
//          else 
//             int pirLED = LOW;
     }
    else      

// High Temp setting and toggle   ------------------------------------------------High Temp HTEMP
    if (wigCommand == "HTEMP")   
      {
       if(DEBUG){ Serial.print(">HTEMP:");
        Serial.print(">highTempVal before:");
        Serial.print(highTempVal);}
        
        highTempEnable = wigSwitch; 
      if(DEBUG){Serial.print(">highTempEnable:");
        Serial.print(highTempEnable);}
        
        highTempVal = wigValueI;
      if(DEBUG){Serial.print(">highTempVal after:");
        Serial.println(highTempVal);}
        
        updateMultiSwitch();
         return 200;       
        
      }
   else   
    
// High Temp Relay Override    ---------------------------------------------------High Temp Relay HTRLY
    if (wigCommand == "HTRLY")   
    {
    if(DEBUG){Serial.print(">HTRLY:");}
       highTempOverride = wigSwitch; 

       updateMultiSwitch();
     if(DEBUG){  Serial.println(highTempOverride);  }     
    if (highTempOverride) {
        pinMode(D3,OUTPUT);
        digitalWrite(D3, HIGH);  //turn on high temp aux fan  relay
         if (ledEnable) {
           pinMode(A0,OUTPUT);
           digitalWrite(A0, HIGH);}  //turn on green led
           return 200; 
    }
    else
    {
           pinMode(D3,OUTPUT);
           digitalWrite(D3, LOW);  //turn off high temp /aux fan  relay
           pinMode(A0,OUTPUT);
           digitalWrite(A0, LOW);  //turn off green overheat LED
          return 200;     
    }
    }
    else   

// OverTemp setting and toggle  ---------------------------------------------------Over-Temp OTEMP
    if (wigCommand == "OTEMP")   
     {  
    if(DEBUG){Serial.print(">OTEMP:");}
        overTempEnable = wigSwitch; 
        overTempVal = wigValueI;
        updateMultiSwitch();
    if(DEBUG){Serial.println(overTempVal);}       
        return 200;  
     }
    else      

// OverTemp Relay Override    ------------------------------------------------------Over-Temp Relay OTRLY
    if (wigCommand == "OTRLY")   
      {
    if(DEBUG){Serial.print(">OTRLY:");}
       overTempOverride = wigSwitch; 
    if(DEBUG){Serial.println(overTempOverride);}

    updateMultiSwitch();    

    if (overTempOverride) {
        pinMode(A7,OUTPUT);
        digitalWrite(A7, HIGH);  //turn on overheat  relay
         if (ledEnable) {
           pinMode(A6,OUTPUT);
           digitalWrite(A6, HIGH);}  //turn on red led
           return 200;
    }
    else
    {
           pinMode(A7,OUTPUT);
           digitalWrite(A7, LOW);  //turn off overheat alert relay
           pinMode(A6,OUTPUT);
           digitalWrite(A6, LOW);  //turn off red overheat LED
           return 200;
     }
     }
    else   
    
// PushingBox Notification toggle  --------------------------------------------PushingBox Notify  NOTFY
    if (wigCommand == "NOTFY")   
    {
      if(DEBUG){ Serial.print(">NOTFY:");}
      notifyEnable = wigSwitch; 
        updateMultiSwitch();
     if(DEBUG){Serial.println(notifyEnable);}    
        return 200;
    }
    else   
    
// Relay Operation  toggle  ------------------------------------------------ Relay 
    if (wigCommand == "RELAY")   
    {
       if(DEBUG){ Serial.print(">RELAY:");}    
       relaysEnable = wigSwitch;
       updateMultiSwitch();       
        if(DEBUG){ Serial.println(relaysEnable); }      
       return 200;
    }
   else   

// Timer Reminder setting and  toggle  ------------------------------------------------ TIMER 
    if (wigCommand == "TIMER")   
    {
       if(DEBUG){ Serial.print(">TIMER:");}    
       rTimerEnable = wigSwitch;
       updateMultiSwitch();
       if (rTimerEnable)
          {startTime = millis();}
       else
          {remainTime=0;}

       if (wigValueI >= 1 && wigValueI <= 60) 
        {rTimerVal = wigValueI;}
        else     
        {rTimerVal = 15;}
        if(DEBUG){ Serial.println(rTimerEnable);
         Serial.println(rTimerVal);}      

       return 200;
    }
   else   
  


// Stealth Mode toggle (all LED functions disabled)  --------------------------Stealth Mode  STEAL
    if (wigCommand == "NOLED")   
     {  
      if(DEBUG){ Serial.print(">NOLED:");}
       ledEnable = wigSwitch; 
        updateMultiSwitch();
       if(DEBUG){Serial.println(ledEnable); }      
        return 200;
     }
    else      

// Shuts off all processing   ---------------------------------------------------------SLEEP
if (wigCommand == "SLEEP")   
      {
      if(DEBUG){Serial.print(">SLEEP:");}
      sleepEnable = wigSwitch;
      updateMultiSwitch();
       if(DEBUG){ Serial.println(sleepEnable); }      
        return 200;     
      }

    else 
    
   return -99;
}   

I GOT IT WORKING!!!

The answer was:

$opts = array(   
  'http'=>array( 
    'method'=>"POST",
      'header'=>"Authorization: Bearer ".$_REQUEST['access_token']."\r\n",
     'content'=>"args=>".$args
      )
);

$context = stream_context_create($opts);

$url = "https://api.spark.io/v1/devices/" . $device . "/" . $method;
$response = file_get_contents($url, false, $context);

echo $response;
1 Like

Nice!!! I have filed that extra content => args in my brain for later retrieval. Thanks for posting your fix!

Sorry I didn’t follow up sooner, but last week was a short work week, and I went out of town over the weekend.

No worries - I feel like I earned it this way! :smile:
It was you’re help that got me aiming in the right direction.
Hope you had a good weekend!
Thanks again!

Slightly corrected -
Edited “args=>” to “args=” as I finally figured out where the extra space was coming from! :smile:

$opts = array(   
  'http'=>array( 
    'method'=>"POST",
      'header'=>"Authorization: Bearer ".$_REQUEST['access_token']."\r\n",
     'content'=>"args=".$args
      )
);

$context = stream_context_create($opts);

$url = "https://api.spark.io/v1/devices/" . $device . "/" . $method;
$response = file_get_contents($url, false, $context);

echo $response;
          

The entire php for both GET and POST:

<?php
// Based on Simple Spark PHP Proxy by wgbartley

$device = $_REQUEST["device"];
$method = $_REQUEST["method"];
if(!$device||!$method) die("device or method param missing\n");

// add access token
$_REQUEST["access_token"] = "your_access_token_here";

$args =$_REQUEST["args"];
if(!$args) {
// create params
$params = http_build_query($_REQUEST);
// make request
$url = "https://api.spark.io/v1/devices/" . $device . "/" . $method . "?" . $params;
$response = file_get_contents($url);
echo $response;}

else 

{

// Create a stream
$opts = array(   
  'http'=>array( 
    'method'=>"POST",
      'header'=>"Authorization: Bearer ".$_REQUEST['access_token']."\r\n",
     'content'=>"args=".$args
      )
);

$context = stream_context_create($opts);

// make request
$url = "https://api.spark.io/v1/devices/" . $device . "/" . $method;
$response = file_get_contents($url, false, $context);
echo $response;
}

// These are for debugging - uncomment to use
//echo " context: ", $context;
//echo $token;
//echo " params: ", $params;
//print_r($context);
//print_r($opts);
//print($args);

?>

I’ve been using this for a couple of years now, but I just had to update this to allow “0” value in args in a POST request. In line 10 it was seeing the 0 as null in
if (!$args)
and treating it like a GET request instead.
Updated to:
if(!$args && !($args == ‘0’))

Updated PHP proxy for Particle on Github