Monday, March 21, 2011

Loading the functions from a powershell script into session memory

.
The answer is ".".
Used like this:
. .\ApowershellScript.ps1
And then within the same powershell session I could do this:
SomeFunctionFromTheAforementionedScript ARandomArgument
And it would work.

I had been calling Process.Start, but the call started failing once I tried adding the call to the powershell function within it.
So this did not work:
1 ProcessStartInfo info = new ProcessStartInfo("powershell.exe");
2 info.Arguments = "{ . C:\\LivingRoom\\ir.ps1; sendIR " + command + " }";
3 info.RedirectStandardError = true;
4 info.RedirectStandardOutput = true;
5
6 info.UseShellExecute = false;
7
8 System.Diagnostics.Process process = Process.Start(info);

So this is what I did get to work:

1 Runspace rs = RunspaceFactory.CreateRunspace();
2 rs.Open();
3
4 Pipeline pipeline = rs.CreatePipeline();
5 Command command3 = new Command(" . C:\\LivingRoom\\ir.ps1", true, false);
6 Command command4 = new Command(" sendir " + command, true);
7 pipeline.Commands.Add(command3);
8 pipeline.Commands.Add(command4);
9 pipeline.Invoke();

It's all about the .

In order to use a Runspace in C#, I had to know the super-secret location of the .net assembly that contained the Runspace code.
C:\Program Files\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0\System.Management.Automation.dll
The fact that they hid it is this odd location is weird. :P
Oh well.

Sunday, March 20, 2011

CoffeeScript and Chirpy

I've found some things that I think are cool:
CoffeeScript 
and
Chirpy

CoffeeScript allows me to use a language other than javascript to write javascript.
Chirpy lets me write that not-javascript inside of Visual Studio. It also does neat things with javascript minimization and packaging.

Saturday, March 19, 2011

World of Warcraft Automation using Coded UI Tests from Visual Studio 2010

Previously I discussed automating repetitive tasks in World of Warcraft using powershell. While that works well, there are some situations where the only thing that will work is a mouse click. SendKeys makes it easy to send keyboard input to a window, but for some reason, I could not find an easy way of sending mouse input using a .Net API. "Easy" is the key word here, I could always try sending a message directly to the window through the Windows API, or involve some expensive third party automated testing tool.

I eventually stumbled upon a new feature in Visual Studio 2010: a coded UI test. The tests themselves are easy to create, the wizard in VS walks you through them excellently. There are plenty of resources on the net that describe how to use this feature in VS, so I'll spare you a redundant and feeble attempt at doing that, and show you how to integrate the result into a powershell script for easy manipulation.

The coded UI test runs very well inside of Visual Studio, but we need to run it externally. The compiled dll from the test project doesn't run by itself though, we require a utility called MSTest to run it.

The finished powershell script integrated with MSTest, looks like this:

Import-Module C:\Windows\Microsoft.NET\Framework64\v4.0.30319\WPF\UIAutomationClient.dll
$a  = [System.Windows.Automation.AutomationElement]::RootElement.FindAll([System.Windows.Automation.TreeScope]::Descendants, [System.Windows.Automation.Condition]::TrueCondition) 
$wow = $a | Where { $_.Current.Name -eq "World of Warcraft" } 
$pattern = $wow.GetCurrentPattern([System.Windows.Automation.WindowPattern]::Pattern)
$pattern.SetWindowVisualState([System.Windows.Automation.WindowVisualState]::Normal)
for($i = 0; $i -lt 80; $i++) { 
     $mstest = "C:\program files (x86)\Microsoft Visual Studio 10.0\common7\ide\mstest.exe"
     Push-Location
     Set-Location "C:\Users\Ogre\Desktop\SVN\Powershell Samples\"
     & $mstest "/testcontainer:testproject1.dll"
     Pop-Location
     Sleep 4
     [System.Windows.Forms.SendKeys]::SendWait("=")
}

The Visual Studio test project was compiled to testproject1.dll and the output was copied into the same directory as this powershell script.

Creating a dll for a particular UI action in World of Warcraft as shown here does take a bit of doing, it certainly isn't as easy as using SendKeys, but you can, using this technique, automate any action in the UI, even the ones that Blizzard ordinarily has blocked from macro and lua programmatic usage.

Note that this only allows for automation of mindless repetitive tasks, if you want a full fledged bot, this falls far short.

Tuesday, March 8, 2011

Android TV Remote

TV remotes are simple devices. All that it takes to make one is an IR emitting diode and a small amount of logic to make the diode blink at the right intervals for the TV to interpret.
The total cost of the materials involved in the construction of such a device is small, probably 5$ at the most. I recently bought a TV remote from Radio Shack and took it apart to confirm the components involved. The device was nearly entirely molded plastic and buttons, plus the one IR diode and the one small chip to control it.

Now, I'm a very lazy person, as this blog post clearly demonstrates, so instead of keeping track of many small fist sized electronic devices that are involved with remote communications, I only want to keep track of only one -- my phone.
This would be a wonderful brilliant solution and a major selling point for whatever phone had incorporated the 5 dollars worth of parts required to make this work, but alas, I know of no phone that currently incorporates an IR LED.
>:P

But my laziness will not be denied, so after a bit of searching on the interwebs, I found a company called global cache which makes devices that facilitate laziness. Particularly ethernet connected IR emitters. So my solution begins to look like this:
Brilliant! Except that is not what I'm going to do. For one thing I opted for a GC-100 which is wired, not wireless. It also connects a relay, a serial, and 3 IR ports via TCP/IP. One of the IR ports has to be used to connect an IR Blaster which actually emits the IR signal.
Brilliant! But android-java is not my forte. So I made a solution that looks like this:
Well, I've removed the whole point of this exercise, which is to control the TV from my phone, but I'll add that back in later. In the meantime, the powershell script is exactly what I want to prototype the application and test that this much, at least, does work.

$msgOnOff = "sendir,2:1,1,37000,1,1,333,167,21,20,21,20,21,61,21,20,21,20,21,20,21,20,21,20,21,61,21,20,21,20,21,61,21,61,21,61,21,20,21,61,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,61,21,61,21,61,21,61,21,61,21,61,21,61,21,61,21,1576,333,83,21,740" + [char]::ConvertFromUtf32(13)
$msgMute = "sendir,2:1,1,37000,1,1,333,166,21,20,21,20,21,62,21,20,21,20,21,20,21,20,21,20,21,62,21,20,21,20,21,62,21,62,21,62,21,20,21,62,21,20,21,62,21,20,21,62,21,62,21,20,21,20,21,20,21,62,21,20,21,62,21,20,21,20,21,62,21,62,21,62,21,1572,333,84,21,740" + [char]::ConvertFromUtf32(13)
$msg = $msgOnOff
$ipaddress = [System.Net.IPAddress]::Parse("192.168.1.70")
$ipendpoint = New-Object System.Net.IPEndPoint -ArgumentList $ipaddress, 4998
$addressFamily = [System.Net.Sockets.AddressFamily]::InterNetwork
$socketType = [System.Net.Sockets.SocketType]::Stream
$protocolType = [System.Net.Sockets.ProtocolType]::Tcp
$socket = New-Object System.Net.Sockets.Socket -ArgumentList $addressFamily, $socketType, $protocolType
$socket.Connect($ipaddress, 4998)
$bytes = [System.Text.ASCIIEncoding]::ASCII.GetBytes($msg)
#$bytes
$socket.Send($bytes)
$socket.Close()

Running this script enabled me to turn the TV on and off programmatically, proving that I had the hardware set up right and that the whole concept would work. The strings: $msgOnOff and $msgMute were taken from using an IR learner and Global Cache's eLearn software.  It took me a bit of fiddling to get the  [char]::ConvertFromUtf32(13) at the end of the strings figured out, and until I did, the script did not work. 


So the next thing that I did was set up a web service that would launch the powershell script. This would enable me to test the set up with a simple web page. That solution looked something like this: 

The web service code looks like this: 


1 [OperationContract]
2 [WebGet]
3 public void ToggleMute()
4 {
5     ProcessStartInfo info = new ProcessStartInfo("powershell.exe");
6     info.Arguments = "-f \"C:\\LivingRoom\\sendirMute.ps1\"";
7     info.RedirectStandardError = true;
8     info.RedirectStandardOutput = true;
9
10     info.UseShellExecute = false;
11
12     System.Diagnostics.Process process = Process.Start( info);
13     return;
14 }

 That code runs a bit slow, so there's about a one second delay between when you launch that code and the TV actually turns off (or mutes itself in this case). I'll have to revisit this in the future and see if I can get it to run more quickly using runspaces or some other trick. 


And then there's the ajax that I use to call the web service: 

    function OnOff() {
        $.ajax({
            url: 'LivingRoom.svc/ToggleOn',
            type: "GET",
            cache: false
        });
    }


Once I verified that this worked from a browser, I was able to publish the website to my local server, and browse to it with my phone's browser, and click on the button that I put on the web page and I finally had my phone operating as a TV remote. 

At this point, the solution works with any device that has a browser (blackberry, iphone, android, random laptop). I could use windows scheduler to toggle the mute or on/off at any time (though I don't know how that would be useful). But what I really want it a native android application that is the User Interface, and not a web page, so after creation of an Android App the solution looks like this: 


public class NotesList extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        final Button button = (Button) findViewById(R.id.Button01);
        button.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                HttpClient httpClient = new DefaultHttpClient();
                HttpContext localContext = new BasicHttpContext();
                HttpGet httpGet = new HttpGet("http://192.168.1.76/LivingRoom/LivingRoom.svc/ToggleMute");
                try {
                    httpClient.execute(httpGet, localContext);
                } catch (ClientProtocolException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });
    }
}


So I've created an Android based TV remote, woot. 

Here's a list of some of the technologies and programs that I used in this little exercise:
Powershell
IIS
aspnet_regiis.exe
Visual Studio 2010
Javascript/JQuery/Ajax
C# Web Service
Eclipse
Windows 7 
Ubuntu Linux
Android Java
Enterprise Architect (for the diagrams)
Paint (for prepping the diagrams)