Sharp aquos TCP/IP control with Client Socket

Hi again,

It took me a while to figure out how RegisterVariable Modul is added (Add Instance > Register Variable, under Misc Vendor).

So now I have a RegisterVariable that is listening to Client Socket that is connected to the TV and it works as I can see the return messages from the TV (e.g. I get strings back like „OK\r“, „0\r“, „1\r“, „ERR\r“ ).

But I am still quite lost. At the moment I use a separate script to send a command to the TV using Client Socket that the RegisterVariable is „connected“ to and I am using to send the command.

CSCK_SendText(37475 /*[Client Socket Aquos]*/, "POWR1   \r"); //Sends the text "Any record" on the client socket with ID 12345

I see that Register Variable has a RegVar_SendText and I am thinking that I should be using it instead of CSCK_SendText.

I am working with the script below that takes what comes in and puts it together (not sure if I need buffering as the strings are short) so I think I need to look for end of line (\r carriage return) in order to know if I received all that the TV sent. I can see that I can catch the carriage return as my if statement echo statement prints.

Can anybody please give me some leads on how to continue.

Thanks

yoggi

<?php

if ($_IPS['SENDER'] == "RegisterVariable") // if the script was called from a RegisterVariable instance
{
    $data  = RegVar_GetBuffer($_IPS['INSTANCE']); // copy data in the buffer of the RegisterVariable instance to $data
    $data .= $_IPS['VALUE']; // attach newly received data to $data
	
	if(strstr($data, "\r")) { // appears to catch carriage return <CR>
	    echo "Found end of line
";
	}else{
	    echo "Nothing found
";	
	}
	
    if (strlen($data) >= 9) // if $data is at least 9 characters long
    {
        $datasets = str_split($data, 9); // split $data into blocks of up to 9 characters
        $data = ""; // empty $data
        for ($i = 0; $i < count($datasets); $i++) // go through all records
        {
            if (strlen($datasets[$i]) == 9)
            {
                echo "received Record: ".$datasets[$i]."
";
            }
            else
            {
                $data = $datasets[$i]; // incomplete data in $data, last record does not have exactly 9 characters

            }
        }
    }

    RegVar_SetBuffer($_IPS['INSTANCE'], $data); // store the contents of $data in the buffer of the RegisterVariable instance

}
?>

If you check for the sender you can combine both parts in one skript and use this script also as an Action Script in IP-Symcon.

I would recommend to use IPS_LogMessage to see whats going on.

You want to send commands to the tv and on the other hand set the current state from the tv to a variable in IP-Symcon.
So first of all you have to create a „device“ tv. Go to the object tree and create an instance called „Dummy Module“.
Under the „Dummy Module“ you create variables for controlling the tv for example a variable Power. Give the variable a variable profile in case of Power ~Switch otherwise create a profile on you own.

You have to set the action from the variable to your action script. For better handling i would recommend to give your variable an ident.


<?

 $object_id = 43497 /*[Geräte\Sharp\Sharp TV\Power]*/; // Objekt ID from the variable
 IPS_SetIdent($object_id, "Power");

?>

Now you can search for this variable with the ident without knowing the exact id with IPS_GetObjectIDByIdent

So one skript could look like this


<?
//part for webfront
 if($_IPS['SENDER'] == "WebFront")
 {
 	$id_dummy = 16961 /*[Geräte\Sharp\Sharp TV]*/; // $object id of the parent, dummy module
	$id_power = IPS_GetObjectIDByIdent("Power", $id_dummy); // gets $object id of the power variable
	SetValue($_IPS['VARIABLE'], $_IPS['VALUE']);
	$state = $_IPS['VALUE'];
	if($state)
	{
		// switch on
		IPS_LogMessage("Sharp TV", "Power On Sharp TV");
		SetValue(52182 /*[Geräte\Sharp\Sharp TV\Last Command]*/, "Power On");
		// .. add command
		//CSCK_SendText(37475 /*[Client Socket Aquos]*/, "POWR1   \r");
	}
	else
	{
		// switch off
		IPS_LogMessage("Sharp TV", "Power Off Sharp TV");
		SetValue(52182 /*[Geräte\Sharp\Sharp TV\Last Command]*/, "Power Off");
		// add command ..
		
	}
 }
 
 
 // part for imcoming messages
 if($_IPS['SENDER'] == "RegisterVariable")
 {
 
 }

?>

In the RegisterVariable part you have to indentify which command belongs to wich variable and and the end set this value with SetValue.

First try this for example with Power and then add every command with a varibale you would like to use.

Hi Fonzo,

I appreciate you taking the time to help me, thanks!

Your last post help me in getting some more understanding but with that said I am still struggling. Could you please clarify a few things for me.

In your post you have two script, is the first one the action script or are the two scripts supposed to be one action script (both have start and end tags)?

If I have Symcon create the action script from within the Power variable under the dummy

SetValue($_IPS['VARIABLE'], $_IPS['VALUE']);

is automatically added to the action script but you have this line in script two (from my test this needs to be in the action script for the on off switch to work in the webfront).

Regarding the five numbered id that is given to objects I think that I have worked out how to translate yours to the one I am getting, all except 52182 in SetValue, where is it pointing, to what objekt?

Ones again thanks for trying to help me!

yoggi

The first script is only needed once for setting the ident of a variable. The bigger second script is the action script and also the script for your register variable.

As mentioned above the bigger second script is the action script for all your variables. You have to add code for every variable.

52182 in this case is only a string variable where you can write in the last command send from the webfront. This is optional and not needed only if you like to see what was send as last command.

Hi Fonzo,

I got your example working, thanks!

One question that I still have, is there an easy way to make the request/command binding (so that only one command can be sent out and that it will need to wait for a respons from the TV or a timeout before an other can be sent out)?

To me it appear that Register Variable is working asynchronous and except responses even if a command is not sent out (the TV dose not send anything unless a request is made but I am currently emulating the TV so I see from my testing that this appears to be the case).

Ones again thanks.

IP-Symcon has step learning curve (at least for me) but the more I read (and figure out) the more sure I get in that I made the right choice to go with it.

yoggi

You can use semaphore for that or additional a buffer or a variable where set blocked or free and check that with a while loop in php.

Yes you have to build this in your script or later a module, but therefore use semaphore and a buffer.

Hi all,

If the RegisterVariable can’t do blocking socket calls would it make sense to use phps stream_socket_client to connect to the TV from within Ip-Symcon?

I think I need to use blocking socket calls as the TV replies with „0“, „1“, „OK“ and „ERR“ when a command is called but with no information what command actually generated the reply.

I have placed the below php script within a normal Symcon script and it appears to work. Although I have no idea if this will cause problems further down the line nor do I have any idea yet on how to integrate it.

The TV keeps the connection open for 3 minutes so I would make sense to reuse an open connection if possible.

I welcome input so please let me know if this approach is bad or if there is a better way.

Thanks in advance.

yoggi

<?
$fp = stream_socket_client("tcp://192.168.1.102:6004", $errno, $errstr, 6);
if (!$fp) {
    echo "Unable to open
";
	IPS_LogMessage("StreamSocketTest", "Unable to open
");
} else {

    fwrite($fp, "POWR1   \r"); // Here I send the power on command
    stream_set_timeout($fp, 2);
    $res = fread($fp, 2000);

    $info = stream_get_meta_data($fp);
    fclose($fp);

    if ($info['timed_out']) {
        echo 'Connection timed out!';
		IPS_LogMessage("StreamSocketTest", "Connection timed out!");
    } else {
        echo $res;
		IPS_LogMessage("StreamSocketTest", "We got this back: " . $res); // Here $res holds the return confirmation from the power on command ("OK\r")
    }

}
?>

Hi,

I am looking for some high level advice and I hope there is a little help to find here.

I am using IPS Client Socket to connect to my TV over tcp/ip, I have a Dummy Module with boolean variables connected to an action script and On Off buttons in the WebFront. The return is handle by a splitter/cutter and a Register Variable.

My problem is that when I toggle, eg. the power switch in the webFront it sends the power on command to the TV and it turns on (replies OK if successful) and IPS sets the power variable that is connected to webfronts OnOff button to on/true but this is done without verifying if the TV actually is on.

Now I want to pull the status from the TV and write the status, but how do I make this work with IPS variables (that are connected to the webfront)?

I have no idea where to start, should I use the variables that the webfront is using or create mirror variables to use with some kind of pull function and then copy over the values to the variables the webfront is using?

Help would be appreciated.

Do you get an answer to the command from the TV? If this is the case you know the current status. Only if the answer was correct then the variable in the web front is set to state on.

I case the TV does send an response to a command you could check if the TV is reachable in the network with ping (Sys_Ping).
Just add a script with a cyclic timer that pings the TV in a defined intervall. If the ping was successfull the TV is on otherwise the TV is off. Depending on the known state you can set the variables in the webfront. But you have to check first if the TV really does not respond to a ping if the device is turned off to standby.


$state = Sys_Ping("192.168.1.10", 1000); //Wait max. 1 second
if($state)
{
SetValue(12345, true); // 12345 is the Variable in the Webfront
}
else
{
SetValue(12345, false);  // 12345 is the Variable in the Webfront
}

Hi Fonzo,

Eg. I send power on command („POWR1“) to the TV and it replies „OK“ if it received command successful and „ERR“ if unsuccessful.

To verify that the TV is on I’ll send the command „POWR?“ and the TV replies „1“ if it is on or „0“ if it is off.

I only want the webfront to show the real status of the TV by pulling the values, how do I combine this in the variable that is connected to webfront with action script (On Off button)?

Thanks

In this case you get a response you can set the variable value depended on the response.


// .. add your command and get the response in $state
if($state == "OK")
{
SetValue(12345, true); // Webfront Variable
}
elseif($state == "ERR")
{
SetValue(12345, false); // Webfront Variable
}
else
{
SetValue(12345, false); // Webfront Variable

}

Just create an extra script. In the script you send your command „POWR?“ and get the response in $state. Then set the value of the webfront variable dependend of the state you got. The Script is then bind to an cylic timer which starts the script every x seconds.


// .. add your command and get the response in $state
if($state == 1)
{
SetValue(12345, true); // Webfront Variable
}
elseif($state == 0)
{
SetValue(12345, false); // Webfront Variable
}

Hi Fonzo,

Thanks for helping!

I have been thinking along the same lines but my problem is were to put these things and how to get them working together.

Eg.

SetValue($_IPS['VARIABLE'], $_IPS['VALUE']); // WebFront set variable

in the „if ($_IPS[‚SENDER‘] == „WebFront“) {“ part sets the variable but the „OK“ arrives in the „if ($_IPS[‚SENDER‘] == „RegisterVariable“) {“ part and I don’t know how to combine these two with a if statement before the switch is flipped and the variable updated!

Trimmed version of my actions script


<?
 $id_dummy   = 49081 /*[Aquos TV\Dummy Module Aquos TV]*/;
 $id_sending = IPS_GetObjectIDByIdent("Sending", $id_dummy); // gets $object id of the sending variable/flag
 
 $id_power   = IPS_GetObjectIDByIdent("Power", $id_dummy); // gets $object id of the power variable

// Part for webfront
if ($_IPS['SENDER'] == "WebFront") {

	// is Client Socket connected and not waiting for return confirmation (102 Instance is active, >= 200 Instance is faulty)
	// are we sending, we can only send command if $id_sending is false
	if ( (IPS_GetInstance( 34862 /*[Client Socket (Aquos TV)]*/ ) ["InstanceStatus"] ) < 200 && !GetValueBoolean($id_sending))
    {
		SetValue($_IPS['VARIABLE'], $_IPS['VALUE']); // WebFront set variable
        
		$state = $_IPS['VALUE'];
                $sender = $_IPS['VARIABLE'];
		
		// 
		IPS_LogMessage("Action Script Aquos TV", "sender: " . $sender . " state: " . $state);
		
		// are we getting power on or power off from WebFront?
        if ($sender == $id_power) {
		
		// Set Sending to true to prevent sending more then one command at the time
		SetValueBoolean($id_sending, true);
		
			if ($state) { // 1 as in true
                // switch on TV
                RegVar_SendText(47048 /*[Client Socket (Aquos TV)\Register Variable Aquos TV]*/ , "POWR1   \r");
                IPS_LogMessage("Aquos Action Script", "Command sent to TV: " . "'POWR1   \\r', Power On");    
            } else {
                // switch off TV
                RegVar_SendText(47048 /*[Client Socket (Aquos TV)\Register Variable Aquos TV]*/ , "POWR0   \r");
                IPS_LogMessage("Aquos Action Script", "Command sent to TV: " . "'POWR0   \\r', Power Off");
            }
        }
    }
}

// Part for imcoming messages, RegisterVariable
if ($_IPS['SENDER'] == "RegisterVariable") {
    
    $data = RegVar_GetBuffer($_IPS['INSTANCE']); // copy data in the buffer of the RegisterVariable instance to $data 
    $data = $_IPS['VALUE']; // attach newly received data to $data
	
	receiveCommand($data); // will move receive to own function
    // IPS_LogMessage("Aquos Action Script", "Return from TV: " . $data);
	
	// Set Sending flag to false so a new command can be sent out (37830 /*[Aquos TV\Dummy Module Aquos TV\Sending]*/)
    SetValueBoolean($id_sending, false);
}

?>

In your case it makes no sense to set the variable directly from the webfront because you get a response.
So first of all delete


 SetValue($_IPS['VARIABLE'], $_IPS['VALUE']); // WebFront set variable 

in the if ($_IPS[‚SENDER‘] == „WebFront“) part.

So you are woundering how is the state then set? The state is allways set via the part if ($_IPS[‚SENDER‘] == „RegisterVariable“), because there you get the response. For example if you press a button in the webfront first of all the variable does not change. It changes it the moment of the response you get from your TV.

For a continous check of the TV you have to add a third part


// Part for check the state with cylic timer 
if ($_IPS['SENDER'] == "TimerEvent") { 
     
    // check state 
    RegVar_SendText(47048 /*[Client Socket (Aquos TV)\Register Variable Aquos TV]*/ , "POWR?   \r"); 
} 

Then add add cyclic timer that starts the script every x seconds. Now every time when the script is executed from the cyclic timer a command is send to the TV to ask for the current state. The response returns as allways in the if ($_IPS[‚SENDER‘] == „RegisterVariable“) part. In the part from the „RegisterVariable“ the value is set. So you have to check what kind of response you have and set the variable dependend of your response you got from the TV.

Hi again,

Yes this makes more sense to me now… but I have one question…

Should I use something along the lines of

SetValueBoolean(52847 /*[Aquos TV\Dummy Module Aquos TV\Power]*/, true);

as I can’t get

SetValue($_IPS['VARIABLE'], $_IPS['VALUE']); // WebFront set variable

to work (I tried to hard code $_IPS[‚VARIABLE‘], and $_IPS[‚VALUE‘] but without any luck).

Thanks for helping!

yoggi

This one works better because it is independent of the trigger.

I’ll have a try at this, thanks for your help!

yoggi

Hi again,

I need to temporally store what is clicked in the WebFront (what OnOff button I am trying to switch / what command should be sent to the TV) so that I can pair it up with the reply I get back from RegisterVariable so that I can set the variable that toggles the switch, how do I do this?

I have tried to use global variabels and super GLOBALS[‚variableName‘] but nothing works.

I need to communicate / transfer values between the „if ($_IPS[‚SENDER‘] == „WebFront“) {“ part and the „if ($_IPS[‚SENDER‘] == „RegisterVariable“) {“ part of an action script, do I need to use a IPS tree variable? Or is there an other way?

Thanks

yoggi

If you use a script I think it is the easiest way to store the information in an IP-Symcon variable in the object tree and compare this value with your information you get. If this would be not a skript but a PHP module you would use SetBuffer to store the data temporary.

Hi Fonzo,

Thanks for the translation linking and working late! But it’s not needed as i use Chrome to translate the German webpages and it works just fine.

If I learn enough PHP I’ll try to create a IPS module.

When creating a module can IPS components like Client Socket, splitter/cutters etc. be utilized or dose everything need to be created in PHP(from scratch)?

yoggi

You will find the necessary documentation for PHP module SDK here.

No there is no need to create this from scrath. Every instance in IP-Symcon has a guid as indentifier. If you create a device in a php module you can create the nessesaary Io for example clientsocket automaticly. For help you can use PHP Modul Dataflow Generator for creating a guid and a skeletal structure for a php module.