Wednesday, September 18, 2013

Chatting with Web Sockets

Web Sockets enable direct socket connections between a web browser and a web server.
Newer versions of PAW support text based Web Sockets. This post shows how to build a small Web Sockets based chat server.

If you have ever tried coding a web based chat server you have surely noticed that the task is not as easy as it might seem at the first look. You have to deal with sessions and have to synchronize clients and so forth. That’s one of the reasons why I never did that ;).
We will see that with Web Sockets there are only a few lines of code necessary on the server side.

I will not go into much detail when it comes to the HTML part, this is standard and everybody can google that.
What I will explain in detail is the PAW setup and the server side BeanShell script included in implementing the chat server.

Configuring the Web Socket Handler

To enable Web Socket support for your PAW server, we have to insert and configure the Web Socket handler inside the handler.xml file. The file is located inside the conf folder of your PAW installation directory . The installation directory is normally /sdcard/paw. Inside the handler.xml file the installation directory is referenced as [PAW_HOME].

The handler can be places right in front of the configuration file inside the <handlers>...</handlers>
tag:

<handler status="active">
    <name>WebSocket Handler</name>
    <description>WebSocket Handler</description>
    <removable>true</removable>
    <id>websocket</id>
    <files/>
    <params>
      <param name="websocket.class" value="org.paw.handler.android.websocket.WebSocketHandler" />
      <param name="websocket.basedir" value="[PAW_HOME]" />
      <param name="websocket.config" value="[PAW_HOME]/webconf/websocket.conf" />
    </params>
  </handler>

There are two important parameters in that handler definition… basedir and config.

Let’s start with config. The parameter config specifies the location of the Web Socket definition file. This file defines rules that describe which BeanShell script (or Java class) to call if a Web Socket connection requesting a specific protocol comes along.

A Web Socket communication can specify a protocol to use, which makes it possible for the server to react differently even if listening to the same port.
A common protocol type is chat which the client sends to the server within the header when the connection is established. You can also define your own protocol, it’s just a text.

In our example the web browser will send a different protocol for each chat room which makes it possible for the server to distinguish them. So if a chat room is called talk, the protocol will be chat.talk.

The other parameter basedir defines the base directory of the BeanShell scripts which are defined inside the Web Socket configuration file.

In the next step, we’ll create the Web Socket config file.

Web Socket Config File

As defined in the handler definition, create a file called [PAW_HOME]/webconf/websocket.conf with the following content:

# Format:
# Protocol:Bsh script (.bsh extension) or class name
#
chat.*:html/websocket/websocket_chat.bsh

That’s it, actually quite simple. I’ll quickly explain the syntax.
The parameters are devided by colons.

First parameter is the protocol which is defined as a regular expression. So in our case the server will call the script html/websocket/websocket_chat.bsh for all protocols starting with chat. Now you already know the second parameter which is the BeanShell script to call.

Actually you can also use a Java class (or performance reasons) but this will not be handled inside this post. More about how to get this working with Java classes can be found inside the PAW Functions section of the PAW web interface.

The next step is to create the BeanShell script.

The BeanShell Script

Before creating the script, some infos in advance.
The handler sets some variables before it calls the script. These variables are action, message, sockets and socket.
The action variable tells us something about the state of the communication. Possible values are connect, disconnect  or text. The state important for us is text because it indicated that a text message has been sent by a client.

If text is set, there is also a variable called message which contains the message itself.

Let’s now have a look at the code, because I think will make things clearer.
Create a file called [PAW_HOME]/html/websocket/websocket_chat.bsh
 with the following content:

import de.fun2code.android.pawserver.websocket.WebSocketMessage;

if(action.equals("text")) {
    for(sock : sockets) {
        try {
            WebSocketMessage.sendMessage(message, sock);
        }
        catch(e) {
          sock.close();
        }
    }
}

That’s the complete server side code. First thing that is checked is if the action variable is set to text which indicates that a message text is available inside the message variable.

If a message is present the code iterates over the sockets collection. The sockets collection contains all client socket connections that have the same protocol.
The socket collections are grouped by Web Socket protocol names, so we are sure that all sockets inside the collection belong to the same chat room.
As mentioned above, the web browser sends different Web Socket protocol names for each chat room (chat.>chatroom>).

So all that is left is to send the incoming message to all connected client. This is done by the following line:

 WebSocketMessage.sendMessage(message, sock);

The try/catch block is there to close a socket if something goes wrong.

One variable that is not present in the code and therefore was not handled until now is the socket variable. This variable contains the socket of the client that delivered the message.

The HTML File

The only thing that is missing is now the HTML file that is responsible for opening the Web Socket connection from the web browser. This is actually a XHTML file because it contains some additional BeanShell code.

The file can be downloaded from the link below. Just copy it into the [PAW_HOME]/html/websocket/ directory.
Now you can start your browser and call the XHTML file by inserting the following address into your browser’s address bar:

http://<ip>:<port>/websocket/chat.xhtml

Web Socket Chat

If everything goes well, the Web Socket chat server should be up and running.
In case of questions, write a comment or send me a mail.

Happy coding :)

Links

XHTML File: websocket_chat_xhtml.zip

Monday, September 16, 2013

PAW - Build Your Own Server


A lot of people have been asking about the PAW source code.
PAW is not Open Source, so (for the time being) you cannot get the source.

Nevertheless … it is now possible for developers to build their own PAW based apps for private and educational purposes. If you plan to use PAW in a commercial product, please drop me a line.

To make this easy, the PAW source code has been restructured.
A sample project along with documentation and a sample APK can be downloaded form the links listed below.
The process of creating a PAW based app should quite easy. Please read the linked documentation for detailed instructions.

 … happy coding! :)

Links:

Documentation: Build_Own_PAW_Server.pdf
Eclipse Project: BuildOwnPawServer.zip
Sample APK: BuildOwnPawServer.apk

Sunday, December 30, 2012

PAW - Using other Languages with CGI

This post is about using other languages apart from BeanShell and PHP. PAW includes a CGI Handler to execute scripts by using the Common Gateway Protocol (CGI). This handler is also used by the PHP plugin to call the CGI version of PHP. The handler is defined inside the file PAW_HOME/conf/handler.XML. Instead of using PHP we will use Perl to create a simple web page.

Finding the Executable Path

First thing to do is to install the SL4A and Perl APK from the Android Scripting Project: http://code.google.com/p/android-scripting/downloads/list After installing the APKs and extracting Perl it's time to find out where the Perl executable is located. One way to do it is to execute the Perl interpreter and to use a terminal emulator and run the ps command. In the case of Perl the executable is located here: /data/data/com.googlecode.perlforandroid/files/perl/perl

CGI Configuration

Now it's time to edit the PAW handler configuration. Open the file PAW_HOME/conf/handler.XML and add the following lines below the Basic Auth Handler configuration:
 <handler status="active">
    <name>Perl CGI  Handler</name>
    <description>Perl CGI  Handler</description>
    <removable>true</removable>
    <id>perlCgiHandler</id>
    <files />
    <params>
      <param name="perlCgiHandler.class" value="org.paw.handler.AndroidCgiHandler" />
      <param name="perlCgiHandler.root" value="[PAW_HOME]/html" />
      <param name="perlCgiHandler.suffix" value=".pl" />
      <param name="perlCgiHandler.runwith" value="/data/data/com.googlecode.perlforandroid/files/perl/perl" />
      <param name="perlCgiHandler.sl4a" value="true" />
      <param name="perlCgiHandler.ENV_TMPDIR" value="[PAW_HOME]/tmp" />
    </params>
  </handler>
Let's have a look at the parameters. The class parameter defines the handler to use. In our case this is the CGI Handler. The next parameter is the root parameter which specifies the directory the scripts are located. Subdirectories are also included. The suffix parameter defines the filename extension for the scripts. The runwith parameter is the most important one, it defines the location of the CGI binary. If the sl4a is set to true the environment variables AP_HOST and AP_PORT are set. Because this information is read from logcat entries, SL4A should be started right before the startup of PAW. Otherwise it might not possible for the handler to extract the SL4A configuration. The last parameter sets the TMPDIR environment variable. All parameters starting with ENV_ are used to set environment variables. Now the PAW configuration is complete and we can start to write a test CGI script.

The CGI Script

We will create a test CGI script inside the PAW_HOME/html directory called test.pl. The test script looks like this:
print "Content-type: text/html\n\n";

print "Hello world!\n";
After starting PAW and entering the URL http://<ip-address>:8080/test.pl into the address bar of the browser the following text should be displayed:
Hello world!

Conclusion

The Android Scripting Project offers many more interpreters. It should be possible use many of them together with PAW, as long as you can get them to work from the command line.

Monday, August 6, 2012

Cache Beacon (beta) - Introduction


This is a post about the Android app Cache Beacon that supports Wireless Cache Beacons on Android.
Garmin® introduced Wireless Beacons in the form of their Chirp™ device almost two years ago.

Cache Beacon is no longer available at Google Play.
The reason is that there is now an official ANT+ Plugin Sampler that includes the functionality of Cache Beacon.
It also allows to write Chirps which was not possible with Cache Beacon and is more stable.
Cache Beacon was ok as long as there was no other implementation of the protocol.

The ANT+ Plugin Sampler can be found here: https://play.google.com/store/apps/details?id=com.dsi.ant.antplus.pluginsampler

A Wireless Beacon can contain cache information like cache name, coordinates and hints.
These information is transmitted via the ANT+ protocol. Some of the Garmin GPS devices support these beacons.
Accessing the information from other devices is complicated, because most devices lack an integrated ANT+ chip.

There are solutions for iPhones and iPads by purchasing a separate BlueTooth ANT+ adapter.
Unfortunately these adapters are quite expensive.

Although the ANT+ Geocaching Device Profile is open there didn't exist a solution for Android devices to access Wireless Beacon until now.
Cache Beacon is an Android app that makes it possible to read the beacon information.

Note: The app is still in beta, so there might be bugs.

To use this app a Sonx Xperia device or an Android device with USB host support is needed.

The maximal distance varies from device to device. When testing, the max. distance with the Xperia device was approx. 2 meters. With an USB adapter it was possible to stay up to 4 meters away.



Sony Xperia Devices

There are some Sony Xperia devices that have an integrated ANT+ chip.
The app should work with these devices without any modification.

Sony Xperia pro


Here is the list of supported Sony devices:
Sony Xperia arco S
Sony Xperia S 
Sony Xperia ion 
Sony Live with Walkman 
Sony active
Sony Xperia arc 
Sony Xperia arc S 
Sony Xperia mini
Sony Xperia mini pro
Sony Xperia neo
Sony neo V 
Sony Xperia pro
Sony Xperia ray
Sony Xperia X8
Sony Xperia X10 mini
Sony Xperia X10 Mini pro

The app has been tested with a Sony Sony Xperia pro (Android 2.1).

USB Host Mode

In addition Android since version 3.1 supports USB Host mode together with an USB OTG adapter.
If USB host mode is supported by the Andrdoid device an USB2 compatble ANT+ USB adapter can be used to add ANT+ support.

USB OTG Apter and SUUNTO Movestick Mini


This has been tested with the following configuration:
Galaxy Nexus, SUUNTO Movestick Mini

After starting the app, the app will tell you if USB host is supported or not.

Result Intent

The app can be also called from another app by using a Result Intent.
The Intent Action to use is: de.fun2code.android.cachebeacon.SEARCH

The resulting Intent contains some Intent Extras.
Here is the list:

NameTypeDescriptionExample
BEACON_NAMEStringCache NameGC123456
BEACON_HINTStringHintfollow the white rabbit
BEACON_LATITUDEDoubleLatitude49.02056660503149
BEACON_LONGITUDEDoubleLongitude8.355349972844124
BEACON_VISITSIntegerVisit Count4
BEACON_LAST_VISIT_DATELongMs since 1.1.19701344249202000
BEACON_BATTERYStringBattery StatusOk


Links

Google Drive: Cache Beacon

Monday, June 25, 2012

Tinkering with PAW

This blog post is about using Tinkerforge modules together with PAW Server for Android.
As an example a volume control for Android is build.



The Setup
The following image shows the components needed to build the volume control.

Component Overview

The LCD and Poti Bricklets are connected to the Master Brick which is connected via USB to a PC running the brickd (Brick Daemon).
The Poti is used to control the volume of the phone. The values will be displayed on the LCD.

Below is an image of the  setup in action.

Complete Setup


Tinkeforge Classes
Tinkerforge offers a set of language bindings which also includes a Java JAR package.
Because PAW needs DEXed classes the Tinkerforge JAR file has to be converted into DEX format.

To make live easy, here is the link: Tinkerforge_dex.jar

To make the file usable for PAW, copy it int the /sdcard/paw/webconf/dex folder and restart the server.

Inside the Beanshell Console of the PAW web interface you can run the following code to check if the file has been loaded.

print(server.props.get("serviceContext").getDexClassLoader());

For me, the output looks like this:
dalvik.system.DexClassLoader[/mnt/sdcard/paw/webconf/dex/webapp_dex.jar:/mnt/sdcard/paw/webconf/dex/Tinkerforge_dex.jar]

If the output includes the Tinkerforge_dex.jar file, everything should be ok.


Bricklet UIDs
In order to talk to the right Bricklets (LCD and Poti) the UID of these components is needed.
Inside the scripts provided in this post, you have to exchange the connection IP address and Bricklet UIDs accroding to your setup.

To find out the UIDs we can ask the Master Brick obout its configuration.

useDexClasses();

import com.tinkerforge.IPConnection;

// Change IP address!
host = "10.0.0.13";
port = 4223;

ipcon = new IPConnection(host, port); // Can throw IOException

ipcon.enumerate(new IPConnection.EnumerateListener() {
    public void enumerate(String uid, String name, short stackID, boolean isNew) {
        if(isNew) {
            $$.print("Name: " + name);
            $$.print(" | UID: " + uid);
            print(" | Stack ID:" + stackID);
        }
    }
});

Thread.sleep(1000);
ipcon.destroy();

With my setup the output looks like this:
Name: Master Brick 1.0 | UID: apaYNJF7xmN | Stack ID:1
Name: Rotary Poti Bricklet 1.0 | UID: 9BY | Stack ID:2
Name: LCD 20x4 Bricklet 1.0 | UID: 9dj | Stack ID:3


Volume Control Script
One note  about the script...
The script uses polling which is not ideal, actually listeners should be used.
Polling is used for the sake of simplicity.

After we have connected the components and found out the UIDs we can run the volume control script.
Remember to change the IP number and the UIDs.

useDexClasses();

import android.media.AudioManager;
import android.content.Context;
import de.fun2code.android.pawserver.PawServerService;

import com.tinkerforge.IPConnection;
import com.tinkerforge.BrickletRotaryPoti;
import com.tinkerforge.BrickletLCD20x4;

r = new Runnable() { public void run() {

    MAX_LABEL = "Max Volume: ";
    DEGREE_LABEL = "Degree: ";
    VOLUME_LABEL = "Volume: ";

    service = server.props.get("serviceContext");
    audioMgr = service.getSystemService(Context.AUDIO_SERVICE);
    maxVol = audioMgr.getStreamMaxVolume(AudioManager.STREAM_MUSIC);


    /*
      UID and IP settings ... these have to be changed!
    */
    host = "10.0.0.13";
    port = 4223;
    UID_LCD = "9dj";
    UID_ROP = "9BY";

    ipcon = null;

    lastVol = -1;
    lcdFirst = true;

    while(true) {
        try {
            // Make sure we have a valid connection
            if(ipcon == null) {
                ipcon = new IPConnection(host, port);
                rop = new BrickletRotaryPoti(UID_ROP);
                ipcon.addDevice(rop);

                lcd = new BrickletLCD20x4(UID_LCD);
                ipcon.addDevice(lcd);
        
                lcd.backlightOn();
            }

            if(lcd.isButtonPressed((short) 0)) {
                break;
            }

            deg = rop.getPosition();
            pos = deg + 150;
            vol = pos * maxVol / 300;
            
            if(lastDeg != deg) {
                if(lcdFirst) {
                    lcd.clearDisplay();
                    lcd.writeLine((short) 0, (short)0, MAX_LABEL + maxVol);
                    lcd.writeLine((short) 1, (short)0, DEGREE_LABEL + deg);
                    lcd.writeLine((short) 2, (short)0, VOLUME_LABEL + vol);
                    lcdFirst = false;
                }
                else {
                    lcd.writeLine((short) 0, (short) MAX_LABEL.length(), "" + maxVol + "  ");
                    lcd.writeLine((short) 1, (short) DEGREE_LABEL.length(), "" + deg + "  ");
                    lcd.writeLine((short) 2, (short) VOLUME_LABEL.length(), "" + vol + "  ");
                }
            }

            if(lastVol != vol) {
                audioMgr.setStreamVolume(AudioManager.STREAM_MUSIC, vol, 0);
            }

            lastDeg = deg;
            lastVol = vol;
        }
        catch(e) { }

        // Wait 100 millis until we poll again
        Thread.sleep(100);
    }

    lcd.clearDisplay();
    lcd.writeLine((short) 0, (short) 0, "Bye bye ...");
    Thread.sleep(1000);
    lcd.clearDisplay();
    lcd.backlightOff();

    ipcon.destroy();
    ​
}};

t = new Thread(r);
t.start();

Some notes about the script:
  • If button 0 of the LCD is pressed, the script will terminate.
  • The Android AudioManager is used to control the music stream volume.
The below picture shows how the display looks like on the LCD.

LCD Output


Android restarts the PAW service from time to time (for whatever reason). So if the scripts stops working just restart it again.
You can also put the script (name is something  like S_tf_volume.bsh) inside the /sdcard/paw/etc/init/1 folder to make sure it's run each time the servers starts up.

Hope this was interesting ... have fun :)

Tuesday, March 20, 2012

PAW Runtime & PHP

PAW Runtime has been updated to support PHP.
To install PHP for the runtime version of PAW, download the file PawRuntime_PHP_Setup.zip (link below) and unzip it to /sdcard of your Android device.

After starting PAW Runtime a PHP menu entry should be available.
After selecting the entry the page shown below should appear...

PHP Setup
Make your selections and press the Install button. PHP should be available after a restart of PAW Runtime.

If you wold like to get rid of unnecessary files and the menu entry, you can delete the file /sdcard/paw-runtime/webconf/apps/php_setup.conf and everything inside the  /sdcard/paw-runtime/html/php_setup directory except the conf directory.

Links
PAW Runtime
PHP Setup

Update
If you have problems to download above files from the original source, try to use the alternative RapidShare links below:
http://rapidshare.com/files/1766553424/PawRuntime.apk
http://rapidshare.com/files/3080577482/PawRuntime_PHP_Setup.zip

Thursday, February 16, 2012

DavDrive and USB

DavDrive can be used via USB connection. This might come in handy if no WiFi connection is available.

For this to work ADB the Android Debug Bridge has to be installed on the PC.
This is the most complicated part of the setup.

I will not describe how to setup ADB. You will find instructions by asking Google or by watching below Youtube video.


After ADB is set up, the ADB command adb devices should show your device.
In my case (with my Galaxy Nexus) it looks like this:

List of devices attached
01498B1F0C003012    device

Now start DavDrive and execute the following ADB command on your PC:

adb forward tcp:8888 tcp:8888

This will forward the port 8888 of your PC to port 8888 on your Android device.
If you have another port configured use that one.

Now you can use the following URL to access DavDrive on your Android device:

http://localhost:8888

That's it :)

Note: Everything mentioned above is also valid for PAW.