Results 1 to 7 of 7

Thread: Sharp Aquos TV control driver creation

  1. #1

    Post Sharp Aquos TV control driver creation

    Hi Ron and co,

    At the moment I have a rudimentary driver working thanks to Girder’s built-in ‘transport’ and my ambition is that this driver should be configurable from Girder’s Device manager (configurable with a minimum of scripting). I am hoping that you and others on this forum can assist (these posts would hopefully be useful for others to).

    I see this as a learning experience as I am fare from being a programmer so I am sure there are plenty of things that could be done differently and more efficient/maintainable code wise.

    Driver
    Some Sharp Aquos TV’s has RS232 and IP control, utilizing simple protocol.

    E.g. to check if the TV is on or off one would send ‘POWR? ’ and the TV would respond ‘0’ for off and ‘1’ for on. All commands and acknowledge commands are terminated with a carrier return ‘\r’ so it is easily parsed with transports built-in parser.

    The control protocol also have a few shortcomings like the lack of volume up and down, the workaround is to query the TV’s volume, add or subtract to this and then set the volume to this new value.



    To do

    1. Implement volumeUp and volumeDown.

    2. Save TV’s status and pass status (like current channel, volume, input, on off etc.) on to NetRemote (store values in a Lua table when TV is queried).

    3. Create a status/heartbeat function (keep connection alive, TV disconnects after 3min of inactivity) Should also update status for Power, Volume, Mute, Input, Sleep.

    4. Automatic log in if TV asks for user and password (If TV is set up for user and password).
    TV sends 'Login:'
    Girder should send id .. "\r" .. password .. "\r" (needs to be done in one string)

    4. …


    Questions

    1.The volume up and down is causing me the biggest headache at the moment. I have based my script on the Pio1a example and I am using the sendCFF( self, cmd, callback ) function to send commands.

    How do I get a queried value back from function sendCMD( self, cmd, callback ) in order to send a set volume command without getting out of sync (with the returned queried volume value) ? I have not been able to figure this out. I assume I need TXR.TX_REQUEUE_FIRST

    I have a function ('adjust_volume' see attached lua file) that takes volumeUp or volumeDown as a parameter and I call it with volumeUp.

    First I need to get current volume by sending 'VOLM? ' and when I get the volume value (e.g. ‘59’ received) back I need to add one to it and send the set command 'VOLM60 '.


    2. How do I pass a value from a Lua script to NetRemote (to change a text label, a picture or a button)?

    Help and comments would be much appreciated!

    Joachim
    Attached Files Attached Files

  2. #2
    Join Date
    Jan 1998
    Location
    Jupiter, FL
    Posts
    13,553

    Default

    1. Hmm, well just send the get command before you even send the set command... does that work?

    2. You can use the KV system to send values to NetRemote.
    Ron
    No support through PM

  3. #3

    Default

    Hi Ron,

    Maybe it is as simple as that (to call get and after that call set). But what about the "que", isn’t there a chance to get out of sync?

    If I have a 'current' transaction (a non persistent) that blocks and then I send a persistent one, what then? Will the persistent one end up in the que and get sent after the blocking one is finished? Or do we have two ques?

    From the Girder manual
    “Note that multiple transaction can be queued up and sit in the queue until the connection is established.

    At any one time there can only be one 'current' transaction. That is a transaction that
    blocks sending of other transactions until it has either timed-out or received a response.
    There can be any number of transactions in the "persistent" queue. What happens after a
    timeout or data received events depends completely on the script and the return value it
    sends back to it's transaction.”

    I will look into the KV system!

    Joachim

  4. #4
    Join Date
    Jan 1998
    Location
    Jupiter, FL
    Posts
    13,553

    Default

    I think the persistent transaction will get queued up in the persistent transaction queue immediately. (note a persistent transaction shouldn't send anything)
    Ron
    No support through PM

  5. #5

    Default

    Hi Ron,

    (recap)
    To increase or decrease volume I need to get the current volume and then add or subtract to it and then set the volume to the new volume.

    Therefore I first need to call sendCommand ('VOLM? ') (from function volumeAdjust) to get the volume (e.g. '7'). Then I need to build string 'VOLM8 ' and send this again with sendCommand (from function volumeAdjust)

    If I call sendCommands two times in a row, the second sendCommands is called before the date is received back from the first sendCommand call so this doesn’t work.
    Question… after some more reading … can I use TX_CONTINUE (Pass the data to the next transaction.) in the above sentence?

    If I neste the second sendCommand within the first sendCommands it seems to work see (code below). Will this cause problems? Is there a more correct way of doing this?

    I have read the Transport section in the manual many times but I can’t fully grasp how it works. Anny chance you could extend this section in the manual?


    Full driver code is in the attached document.

    Code:
    function volumeAdjust( self, value ) -- '1' or '-1'
    
    	sendCommand( self,  'VOLM?   ', function( success, returnData )
    		print( "volume get success? ", success, "returnData", returnData )
    
    		if returnData ~= nil and returnData ~= 'ERR' then -- TV replies 'ERR' if off
    
    			returnData = returnData + value
    
    			-- TV volume values 0-60
    			if returnData < 0 then
    				returnData = 0
    			elseif returnData > 60 then
    				returnData = 60
    			end
    
    			returnData = tostring( returnData )
    
    			while #returnData < 4 do returnData = returnData .. ' ' end -- pad up e.g. '7' to '7   '
    
    			sendCommand( self, 'VOLM' .. returnData, function( success ) -- success (boolean
    				print ( "volume set success? ", success, "volume set", returnData )
    			end)
    		end
    	end)
    	
    end

    Code:
    function sendCommand( self, cmd, callback ) -- e.g. 'POWR?   ' or 'POWR1   ' (sends valid Aquos TV commands of 8 characters)
    
    	if not self.connection then
    		return false
    	end
    
    	if not callback then
    		callback = function( ) end
    	end
    	
    	local retries = 0
    
    	local tx = self.connection:newTransaction(
    		function()
    			-- sent
    			print("sendIP / Data was sent...")
    		end,
    		function( data )
    			-- data
    
    			-- returning data e.g. OK, ERR, 0, 1, 2, 0-60, 0-150
    
    			-- commands that return numbers
    			-- POWR? (0, 1)
    			-- VOLM? (0-60)
    			-- MUTE? (1, 2)
    			-- OFTM? (0-150) sleep timer
    			-- IAVD? (ERR, 1-8) input
    
    			if data == "OK" then -- TV received and acknowledge command
    				print("Command sent", cmd, "returnData", data )			
    				callback( true )
    				
    			elseif data == "ERR" then -- TV received invalid command
    				print("Invalid command, command sent", cmd, "returnData", data )
    				callback( false, data ) -- added data as returnData
    				return TXR.TX_REMOVE
    				
    			-- TV queries return numbers, do we have a number between 0 and 150
    			elseif tonumber( data ) >= 0 and tonumber( data ) <= 150 then
    
    				-- what cmd was called POWR?, VOLM?, MUTE?
    				if cmd == 'POWR?   ' then
    
    					if data == '0' then
    						print ("POWR_OFF")
    						-- callback( true )
    						callback( true, data )
    
    					elseif data == '1' then
    						print ("POWR_ON")
    						-- callback( true )
    						callback( true, data )
    						
    					end
    
    				elseif cmd == 'VOLM?   ' then
    						print("VOLUME", data)
    						callback( true, data )
    						
    				end
    
    			else
    				print("Error could not send")
    				callback( false )
    				return TXR.TX_REMOVE -- Remove the transaction
    			end
    
    		end,
    		function ()
    			-- timeout
    			retries = retries + 1
    			if retries > 2 then
    				print("sendIP / Failed to get devices")
    				callback( false )
    				return TXR.TX_REMOVE	-- Remove the transaction
    			else
    				print("sendIP / Retrying...")
    				return TXR.TX_REQUEUE_FIRST	-- Re-queue the transaction at the beginning of the transaction queue.
    			end
    		end
    	)
    	
        tx:timeout(5000) -- time between retries
        tx:data(cmd .. "\r")
        tx:persistent(false)
    	
        self.connection:send(tx, true)
    
    end
    Attached Files Attached Files
    Last edited by Yoggi; September 8th, 2015 at 02:13 AM.

  6. #6

    Unhappy

    I don't want to give up on Girder but I need to understand Girder’s built-in ‘transport’ better. I am at the technical level that I can see that Girder should be able to do all that I need but I am not a professional programer (if I was I would probably not need a product like Girder but I would write my own code from scratch).

    I understand that promixis is a small company but I wounder how many people have given up on Girder do to the lack of documentation (I have a pm from one on this forum that has given up do to this).

    Maybe free Girder licensees could be given to people that write good tutorials just like the offer for translation of Girder.

    I think you have a grate product (a lot of nice features) so please help users use it to its fullest with just as good documentation and examples!

    Joachim

  7. #7
    Join Date
    Jan 1998
    Location
    Jupiter, FL
    Posts
    13,553

    Default

    Hi Joachim,

    If I call sendCommands two times in a row, the second sendCommands is called before the date is received back from the first sendCommand call so this doesn’t work.
    Question… after some more reading … can I use TX_CONTINUE (Pass the data to the next transaction.) in the above sentence?

    Data flow:
    When a packet of data arrives ( and a packet is defined by the parser ) it first is given to the persistent transactions. If they return TX_CONTINUE the data will continue to flow to the next persistent transaction. If all persistent transactions returned TX_CONTINUE the packet goes to the current transient transaction (transient = NOT persistent). If any transaction wants to consume the data it should not return TX_CONTINUE. If a transaction is done it should return TX_REMOVE

    At any one time there is only ONE transient transaction. So even if you queue two transient transactions only the first of these will be the current transient transaction. returning TX_CONTINUE from it will simply keep it as the current transaction and the 2nd transaction is not used. Once the current transaction times out or returns TX_REMOVE the 2nd will come into play.


    The code you posted in post 5 with the nested command looks exactly as I would do it too. First queue up a transient transaction that queries for the volume level, parse the result then send a volume modify transaction from the callback from the first get volume transaction.
    Ron
    No support through PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •