This website uses cookies for visitor traffic analysis. By using the website, you agree with storing the cookies on your computer.More information

Control your window shutters with JavaFX

If you have remote controlled, electronical, window shutters, continue reading. If you don't have them, this article might not be interesting for you?
I have such window shutters and a lot of windows. I don't own a control center that allows me to automatically open and close my shutters every morning and evening. I do it every day manually. Sometimes sooner and sometimes later - depends on the day of the week.

Why I don't own a control center?
Such control centers are expensive and do not offer expected features. Some of my features are controlling via SMS, controlling via Internet, move shutters to a specific position (not only up and down).

I didn't really search for a solution of my "problem" because it was not a problem, it was an everyday task and it was habitual. Since I own a RaspberryPi, I tried to find useful solutions, not only Hello worlds. That's the reason why I tried to control my window shutters via Raspberry Pi.

The first big problem was, that it was not possible to find a sender for my shutters. The frequency was 433,42 MHz, but there were no ready-to-use solutions. It was not my intention to solder my own sender and record and decrypt the signal. So, I decided for the easy way: Connect an existing remote control with my Pi. It makes no difference for the remote control, if you press buttons manually or a Pi does the job.

It was not a big problem to find some cheap 3V relais. The soldering was fun and not rocket science. Here is the result:

Remote control

Remote control

My remote control got a new brain. It works with and without connected Pi. I didn't damage it :)
The only thing I had to do, was programming every receiver with one (or more) channel of my remote control. Because one button should control all window shutters. But that was a task of 5 minutes.

The hardware was ready and the next step was a fancy client application for controlling my Pi. The plan was a simple application that shows one of my windows. The shutter should move like the original. The application should connect to my Pi via my LAN.
I used JVx and vert.x on server-side for the GPIO control, wrote a nice Deskotp application with JavaFX, some transitions and JVx for the communication to my server. And here is the result:


JavaFX application

The application moves the shutter like its big brother. One feature is transparency on mouse over, because you wanna know the position if you stop it.

And if you are interested how software and hardware acts together:


JavaFX Shutter control

The project was really cool because the source code for the whole thing was minimal, the costs were not comparable to a control center from the manufacturer and I have all features I ever wanted.

Interested in the source code?

Server-side, JVx style:

//----------------------------------------------------
// Application.java
//----------------------------------------------------

public GpioController getController()
{
    GpioController gpio = (GpioController)get("controller");
       
    if (gpio == null)
    {
        gpio = GpioFactory.getInstance();
               
        put("controller", gpio);
    }
       
    return gpio;
}

public GpioPinDigitalOutput getDownPin()
{
    GpioPinDigitalOutput pin = (GpioPinDigitalOutput)get("downPin");
       
    if (pin == null)
    {
        pin = getController().provisionDigitalOutputPin(RaspiPin.GPIO_01, "Down",
                                                        PinState.LOW);
               
        put("downPin", pin);
    }
       
    return pin;
}

//---------------------------------------------
// Session.java
//---------------------------------------------

public void moveDown() throws Exception
{
    GpioPinDigitalOutput pin = getDownPin();
       
    pin.high();
    Thread.sleep(2000);
    pin.low();
}

And my client simply calls:

NetSocketConnection con = new NetSocketConnection("10.0.0.39");
                       
macon = new MasterConnection(con);
macon.setApplicationName("shutter");
macon.setUserName("user");
macon.setPassword("pwd");
macon.setAliveInterval(-1);
macon.open();

macon.callAction("moveDown");

RaspberryPi JavaFX + Sound

Media support is not included in the current JDK8 preview. If you want to play audio files, it's maybe a problem if you think that it's not possible :)

Don't use JavaFX for the job. Simply use Java Sound API. We successfully used it for our tests with Beagleboard-xm and RaspberryPi (jdk7, jdk8 javafx preview).

Here's the source code of our, old but still good, implementation:

/*
 * Copyright 2012 SIB Visions GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 *
 *
 * History
 *
 * 15.12.2005 - [JR] - creation
 */

package com.sibvisions.apps.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Hashtable;
import java.util.Vector;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;

import com.sibvisions.util.type.FileUtil;

/**
 * The <code>AudioPlayer</code> plays audio files. Currently only wav, au and midi files are supported.
 *
 * @author René Jahn
 */

public final class AudioPlayer
{
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // Class members
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  /** thread list for background playback. */
  private static Vector<Thread> vThreads = null;
 
  /** list of dataline connections for playback. */
  private static Vector<SourceDataLine> vSdl = new Vector<SourceDataLine>();
 
  /** Cached audio files. Reduces resource usage during repatedly playback. */
  private static Hashtable<String, byte[]> htAudioCache = new Hashtable<String, byte[]>();
 
  /** sync object. */
  private static final Object SYNC = new Object();
 
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // Initialization
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  /**
   * Invisible constructor because <code>AudioPlayer</code> is a utility
   * class.
   */

  private AudioPlayer()
  {
  }
 
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // User-defined methods
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  /**
   * Gets the current player thread count.
   *
   * @return the number of player threads
   */

  public static int getPlayerThreads()
  {
    if (vThreads != null)
    {
      return vThreads.size();
    }
    else
    {
      return 0;
    }
  }
 
  /**
   * Playback an audio file.
   *
   * @param pFileName the filename
   * @param pBackground <code>true</code> to start playback as background process. The method call returns
   *                    immediately.
   */

  public static synchronized void play(final String pFileName, boolean pBackground)
  {
    AudioPlayer.play(new String[] {pFileName}, 0, pBackground);
  }

  /**
   * Playback multiple audio files.
   *
   * @param pFileName list of file names
   * @param pDelay delay between playback
   * @param pBackground <code>true</code> to start playback as background process. The method call returns
   *                    immediately.
   */

  public static synchronized void play(final String[] pFileName, final long pDelay, boolean pBackground)
  {
    Thread thPlay;
    Thread th;

   
    if (pBackground)
    {
      thPlay = new Thread()
      {
        public void run()
        {
          if (Thread.currentThread() == this)
          {
            if (pFileName != null)
            {
              for (int i = 0, anz = pFileName.length; i < anz; i++)
              {
                AudioPlayer.play(pFileName[i]);
               
                //Use defined delay between playback, but ignore delay after the last track
                if (pDelay > 0 && i + 1 < anz)
                {
                  try
                  {
                    Thread.sleep(pDelay);
                  }
                  catch (InterruptedException ie)
                  {
                    //nothing to be done
                  }
                }
              }
            }
          }
         
          vThreads.remove(this);
        }
      };
     
      if (vThreads == null)
      {
        vThreads = new Vector<Thread>();
      }
     
      //Clear zombies
      for (int i = 0; i < vThreads.size();)
      {
        th = (Thread)vThreads.get(i);
       
        if (!th.isAlive())
        {
          th.interrupt();
          vThreads.remove(i);
         
          th = null;
        }
        else
        {
          i++;
        }
      }
     
      vThreads.add(thPlay);
     
      thPlay.setPriority(Thread.MAX_PRIORITY);
      thPlay.start();
    }
    else
    {
      if (pFileName != null)
      {
        for (int i = 0, anz = pFileName.length; i < anz; i++)
        {
          AudioPlayer.play(pFileName[i]);
         
          //Use defined delay between playback, but ignore delay after the last track
          if (pDelay > 0 && i + 1 < anz)
          {
            try
            {
              Thread.sleep(pDelay);
            }
            catch (InterruptedException ie)
            {
              //nothing to be done
            }
          }
        }
      }
    }
  }
 
    /**
     * Playback a sound file.
     *
     * @param pFileName the filename
     */

    public static void play(String pFileName)
    {
    AudioInputStream ais = null;
 
    AudioFormat adf;
   
    DataLine.Info dli;
   
    SourceDataLine sdl;
   
    byte[] byData = new byte[128000];

    int iData;
   
   
    try
    {
      byte[] byCache = (byte[])htAudioCache.get(pFileName);
     
      if (byCache != null)
      {
        ais = AudioSystem.getAudioInputStream(new ByteArrayInputStream(byCache));
      }
      else
      {
        File fiDirect = new File(pFileName);
       
        //use byte array because most InputStreams do not support "seek"
        //we avoid Exceptions
        if (fiDirect.exists())
        {
          byCache = FileUtil.getContent(new FileInputStream(fiDirect));
        }
        else
        {
          byCache = FileUtil.getContent(AudioPlayer.class.getResourceAsStream(pFileName));
        }

        if (byCache != null)
        {
          cacheFile(pFileName, byCache);

          ais = AudioSystem.getAudioInputStream(new ByteArrayInputStream(byCache));
        }
        else
        {
          throw new IllegalArgumentException("No content found for : " + pFileName);
        }
      }
     
      byCache = null;
    }
    catch (Exception e)
    {
      e.printStackTrace();
      return;
    }

    adf = ais.getFormat();
    dli = new DataLine.Info(SourceDataLine.class, adf);

    try
    {
      sdl = (SourceDataLine) AudioSystem.getLine(dli);
      sdl.open(adf);
     
      synchronized (SYNC)
      {
        vSdl.add(sdl);
      }
    }
    catch (Exception e)
    {
      e.printStackTrace();
      return;
    }

    sdl.start();

    try
    {
      while ((iData = ais.read(byData, 0, byData.length)) != -1)
      {
        sdl.write(byData, 0, iData);
      }
    }
    catch (IOException ioe)
    {
      ioe.printStackTrace();
    }

    sdl.drain();

    synchronized (SYNC)
    {
      sdl.flush();
      sdl.stop();
     
      sdl.close();
     
      vSdl.remove(sdl);
    }

    try
    {
      ais.close();
      ais = null;
    }
    catch (IOException ioe)
    {
      //nothing to be done
    }
   
    sdl = null;
    adf = null;
    }
 
    /**
     * Stop playback of all audio files.
     */

    public static void stopSound()
    {
      synchronized (SYNC)
      {
        if (vSdl != null)
        {
        //stop all playbacks
        for (SourceDataLine sdl : vSdl)
        {
          try
          {
            sdl.flush();
            sdl.stop();
         
            //Don't call this because it crashes the VM and results in a core dump
            //sdl.close();
          }
          catch (Exception e)
          {
            //nothing to be done
          }
        }
       
        vSdl.clear();
        }
      }
    }
   
    /**
     * Caches audio data for later use. If the file is already cached the cache won't
     * be overwritten.
     *
     * @param pFileName the filename
     * @param pData audio data
     */

    public static void cacheFile(String pFileName, byte[] pData)
    {
      cacheFile(pFileName, pData, false);
    }

    /**
     * Caches audio data for later use.
     *
     * @param pFileName the filename
     * @param pData audio data
     * @param bIgnoreCache <code>true</code> to overwrite already cached data, <code>false</code>
     *                     doesn't overwrite cached data
     */

    public static void cacheFile(String pFileName, byte[] pData, boolean bIgnoreCache)
    {
      if (!bIgnoreCache && htAudioCache.containsKey(pFileName))
      {
        return;
      }
     
      if (pFileName != null && pData != null)
      {
        htAudioCache.put(pFileName, pData);
      }
    }
   
    /**
     * Caches an audio file for later use. The file content will be read automatically.
     * If the file is already cached the cache won't be overwritten.
     *
     * @param pFileName the filename
     */

    public static void cacheFile(String pFileName)
    {
      cacheFile(pFileName, false);
    }

    /**
     * Caches an audio file for later use. The file content will be read automatically.
     *
     * @param sFileName Dateiname
     * @param bIgnoreCache true um bereits gecachte Daten zu überschreiben
     */

    public static void cacheFile(String sFileName, boolean bIgnoreCache)
    {
      //don't overwrite cache, if not specified
      if (!bIgnoreCache && htAudioCache.containsKey(sFileName))
      {
        return;
      }
     
      InputStream is = AudioPlayer.class.getResourceAsStream(sFileName);
     
      ByteArrayOutputStream bos = new ByteArrayOutputStream();

    byte[] byData = new byte[128000];
     
      int iData;
     
     
      try
      {
      while ((iData = is.read(byData, 0, byData.length)) != -1)
      {
        bos.write(byData, 0, iData);
      }
   
      htAudioCache.put(sFileName, bos.toByteArray());
     
      bos.close();
      is.close();
      }
      catch (IOException ioe)
      {
        //nothing to be done
      }
    }
   
} //AudioPlayer

Example wav file.

OUYA

Sounds like "Oh Ja" in German ;-)

Our developer console arrived today! What a great day.

First impressions:

OUYA unboxing

OUYA unboxing

 
OUYA Console

OUYA Console

Stay tuned.

NFC Reader with RaspberryPi GPIO

If you read my postings about NFC Reader, you know that I use an USB TTL module for the communication with my NFC Reader (UART mode). If you don't own such a module, it's not a big problem to connect the reader with GPIO pins of your RaspberryPi.

How?

Change /boot/cmdline.txt, from:

dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1

to

dwc_otg.lpm_enable=0 console=tty1

Change /etc/inittab, from:

#Spawn a getty on Raspberry Pi serial line
T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100

to

#Spawn a getty on Raspberry Pi serial line
#T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100

Reboot your Pi.

Connect the Reader with following PINs:

GND -> PIN 6
TxD -> PIN 10 (= GPIO 15)
RxD -> PIN 8 (= GPIO 14)
VCC -> PIN 1 (3,3V) or PIN2 (5,5V)

(GPIO PIN overview)

Use serial port with the name /dev/ttyAMA0 for RxTx and configure RxTx e.g. -Dgnu.io.rxtx.SerialPorts=/dev/ttyAMA0.

Successfully tested with eNFC.

Vaadin 7 beta11 javadoc

Vaadin 7 is still in beta phase. Thats not really a problem, but you don't find a source and/or javadoc archive? Maybe the archives are available, but I couldn't find them!

The source code is available here and in README.TXT you'll find a link to Git of v7.

The heads section contains a link to beta11. Download a snapshot from there and you'll get most source files.

To generate your own javadoc, you'll need some library (jar) files. Simply download complete Vaadin 7.0.0 beta11 archive. This archive contains a lib directory.

Let's create the javadoc

Extract your downloaded source snapshot (e.g. D:\Temp\vaadin-7.0.0.beta11) and create a libs sub-directory. Extract all libraries from beta archive into this directory. Download additional libraries: Portlet API, Servlet API and GWT. (you'll need gwt-servlet.jar and gwt-user.jar). Copy all jar files into the libs directory.

I used following ant task to generate my javadoc:

<target name="vaadin.javadoc">
  <property name="vaadin" location="D:/temp/vaadin-7.0.0.beta11"/>
  <property name="doc" location="${vaadin}/javadoc"/>
  <property name="doc.src" location="${vaadin}/allsrc"/>
  <delete dir="${doc}" />
  <delete dir="${doc.src}" />
  <copy todir="${doc.src}">
    <fileset dir="${vaadin}/client/src/" />
    <fileset dir="${vaadin}/server/src" />
    <fileset dir="${vaadin}/shared/src" />
  </copy>
  <javadoc packagenames="*"
            sourcepath="${doc.src}"
            destdir="${doc}"
            author="false"
            version="false"
            use="true"
            windowtitle="Vaadin 7.0.0 beta 11 (temporary)"
            source="1.6"
            encoding="UTF-8">
    <classpath>
      <fileset dir="${vaadin}/libs">
        <include name="**/*.jar" />
      </fileset>
    </classpath>
    <doctitle>
      <![CDATA[<h1>Vaadin 7.0.0 beta 11 (temporary)</h1>]]>
    </doctitle>
    <bottom>
      <![CDATA[Manually built]]>
    </bottom>
      <link href="http://docs.oracle.com/javase/6/docs/api/" />
      <link href="http://java.sun.com/j2ee/1.4/docs/api/" />
      <link href="http://google-web-toolkit.googlecode.com/svn/javadoc/latest/" />
    </javadoc>
    <jar destfile="${vaadin}/vaadin-7.0.0-beta11-javadoc.jar">
      <zipfileset dir="${doc}" />
    </jar>

Customize the "location" parameter of the properties and use jdk6 or jdk7 to execute the task.

Source code is available in allsrc directory and javadoc is available in javadoc directory or as zip archive.

Good luck and have fun ;-)

Power control with RaspberryPi, JVx and Vert.x

My idea was to create a programmable timer for some lamps at home. I wanted to control the timer via mobile phone (not only smartphone). I decided to use simple SMS'.

The timer app was not really a challenge and the SMS interface was also very straight forward, so I added a little bit network communication and complexity. The result:

Power control

Power control

My Hardware:

  • Raspberry Pi Model B
  • Cinterion TC65i
  • Standard table lamp
  • Solid State Relay (found here)
  • Laptop as cluster client
  • Mobile Phone :)

My software:

My first question was - Which application server should I use for my Pi? I thought that JBoss or Tomcat would be overhead and I would save resources. I decided for Vert.x and a simple socket server. I wanted to show the integration of Vert.x with JVx and so my server got a JVx application with some business logic for publishing messages.

The server "thing" was clear and for reading SMS' I wrote a simple polling app. The app reads SMS from my hardware via RS232 and forwards received SMS via JVx APIs to my server (with Vert.x' NetClient).
I didn't use the EventBus for sending messages becasue I wanted to show the seamless integration of JVx and Vert.x.

The code for forwarding messages:

MasterConnection macon = new MasterConnection(new NetSocketConnection("10.0.0.39"));
macon.setApplicationName("demo");
macon.setUserName("user");
macon.setPassword("password");
macon.setAliveInterval(-1);
macon.open();

macon.callAction("publishMessage", msg.getOriginator(), msg.getText());

The server application is a standard JVx application (only server-side). It uses a standard XmlSecurityManager without the need for a database. The "business logic" is very simple:

public Vertx getVertx()
{
    return (Vertx)get("vertx");
}

public void publishMessage(String pNr, String pMessage)
{
    System.out.println("publishMessage (" + pMessage + ")");
       
    String sNumber = pNr;

    sNumber = sNumber.substring(0, 5);

    //hide last characters
    for (int i = 5; i < pNr.length(); i++)
    {
        sNumber += "*";
    }
       
    JsonObject jsobj = new JsonObject();
    jsobj.putString("number", sNumber);
    jsobj.putString("message", pMessage);
       
    getVertx().eventBus().publish("sms.received", jsobj);
}

I made some tests with vert.x clustering and decided to implement a (very) simple JavaFX application that shows published SMS'. The application contains following code:

vertx = Vertx.newVertx(25502, "10.0.0.11");

EventBus ebus = vertx.eventBus();
ebus.registerHandler("sms.received", new Handler<Message<JsonObject>>()
{
    public void handle(final Message<JsonObject> pMessage)
    {
        Platform.runLater(new Runnable()
        {
            public void run()
            {
                try
                {
                    mdb.insert(false);
                    mdb.setValues(new String[] {"NUMBER", "MESSAGE"},
                                  new String[] {pMessage.body.getString("number"),
                                                pMessage.body.getString("message")});
                    mdb.saveSelectedRow();
                }
                catch (ModelException me)
                {
                    throw new RuntimeException(me);
                }
            }
        });
    }
});

Finally, I created a short video that shows all in action. It shows three applications on the same laptop. The first is the JavaFX application that shows published SMS. The second is the Power control (includes SMS check), started via PuTTY. The third application is the server instance, started via PuTTY. You can see a table lamp that will be turned on and off with SMS, sent from a smartphone.

Enjoy it :)


Power Control with RaspberryPi

Vert.x + JVx

Do you know vert.x?

It's like node.js but written in Java and without JavaScript limitations. It's very powerful and easy to use. I don't describe features of vert.x or tell you how it works. If you want to know more about it, you'll find everything you need on the official site.

How and why do we use vert.x?

We simply tried it out to find out how it works and if an integration with JVx makes sense. We started a simple Research project with some goals:

  • Create a simple http server that will run without an application server, e.g. on a Raspberry Pi
  • Create a simple net/socket server, also for Raspberry Pi
  • Deploy an existing JVx application (e.g. FirstApp) and connect to the new server
  • Integrate the EventBus in an existing JVx application
  • Create a simple JavaScript app (show data in a grid) with jQuery, jQueryUI and vert.x EventBus
  • Use EventBus in Cluster mode (Java IPC)

The documentation of vert.x is great and there are a lot of examples, not what we needed but good for a quick start.

It was easy to create a http and socket server. The only problem was that everything was asynchronous and JVx expected synchronous calls. The HttpConnection of JVx worked without modifications because the JDK solved everything. We didn't use the vert.x http client.

It was a little bit tricky to implement an IConnection for socket communication because the server has to know when a command ends. It only reads a stream and does not know the protocol! We didn't introduce a new protocol, instead we wrote a delimiter after each command. This worked like a charm.

After we had http and socket support, the usage of an existing JVx application was easy. We copied existing files and it worked out-of-the-box. That was as expected ;-)

What about the event bus?

With JVx we have a super fast and simple client/server communication and it's possible to send messages from the client to the server, but the client polls. It's not live!

The event bus offers more power and flexibility. We thought it would be a great benefit for JVx applications or applications written in technologies that are supported from vert.x e.g. JavaScript.

It's already possible to use JVx' REST interface from non Java applications but if you use vert.x it would be cool to use the event bus.

The EventBus support was soo easy because the API is very nice and simple. It's enough to register a handler (like a listener) for a specific address (= string). After the registration you'll receive events from the bus :)

We had some problems with clustering vert.x because we didn't read the (whole) documentation and the information was in a different place as expected. If you use vert.x embedded and start multiple applications with different Vertx instances, be sure to use free cluster (communication) ports (see manual):

-cluster-port If the cluster option has also been specified then this determines which port will be used for cluster communication with other vert.x instances. Default is 25500. If you are running more than one vert.x instance on the same host and want to cluster them, then you'll need to make sure each instance has its own cluster port to avoid port conflicts.

We had to create Vertx instances with a specific port, e.g. 25501, 25502 (for the second and third application):

Vertx vertx = Vertx.newVertx(25501, "10.0.0.11");

Without port and host, the instance is not clustered!

The last goal was a simple JavaScript application. Here is a screenshot:

JVx with Vert.x and JQuery

JVx with Vert.x and JQuery

The application connects with username and password and retrieves data from a database via business logic (standard JVx). We used an existing JVx application and wrote one html page for our JavaScript application. Here is the source code:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>JVx + vert.x + jQuery</title>
 
<link rel="stylesheet" type="text/css" media="screen" href="css/jquery-ui.custom.css" />
<link rel="stylesheet" type="text/css" media="screen" href="css/ui.jqgrid.css" />

<script src="js/jquery-1.7.2.min.js" type="text/javascript"></script>
<script src="js/i18n/grid.locale-en.js" type="text/javascript"></script>
<script src="js/jquery.jqGrid.min.js" type="text/javascript"></script>
<script src="http://cdn.sockjs.org/sockjs-0.2.1.min.js"></script>
<script src="js/vertxbus.js"></script>
<script type="text/javascript">
  $.jgrid.no_legacy_api = true;
  $.jgrid.useJSON = true;
</script>
<script type="text/javascript">
jQuery(document).ready(function(){
  $.jgrid.defaults = $.extend($.jgrid.defaults,{loadui:"enable"});

  jQuery("#grid").jqGrid(
  {
    datatype: "local",
    height: 400,

    colNames:['ID','PLZ-ID', 'ZIP', 'STRA-ID', 'Street', 'House #', 'Floor', 'Door #'],
    colModel:[
                {name:'ID', width:60, sorttype:"int"},
                {name:'POST_ID', hidden:true},
                {name:'POST_PLZ', width:50, align:"right", sorttype:"text"},
                {name:'STRA_ID', hidden:true},
                {name:'STRA_NAME', width:200, sorttype:"text"},        
                {name:'HAUSNUMMER', width:50, align:"right", sorttype:"int"},          
                {name:'STIEGE', width:70, align:"right", sorttype:"int"},              
                {name:'TUERNUMMER', width:60, align:"right", sorttype:"int"}
                ],
   
    multiselect: false,
    rowNum: 200,
    forceFit: true,
    loadonce: true,
    caption: "Address data"
});

eb = new vertx.EventBus("http://10.0.0.11:8080/eventbus");

eb.onopen = function()
{
    eb.send('jvx.createSession',
            {application: 'demo', username: 'rene', password: 'rene'},
            function (reply)
    {  
      eb.send('jvx.fetch',
              {sessionId: reply.sessionId, object: 'adrData'},
              function (reply2)
      {
        gdata = reply2.data;

        for(var i = 0; i <= gdata.length; i++)
       {
         jQuery("#grid").jqGrid('addRowData', i + 1, gdata[i]);
       }
     });
   });    
};

});
</script>
</head>
<body>
  <div id="GridPane">
    <table id="grid"></table>
  </div>
</body>
</html>

The authentication is hardcoded, of course. It's not a problem to show a login page, but not necessary for our project.

Summary

We have a great integration of JVx for vert.x and it's now possible to use JVx on remote hosts without application server. Simply use Vert.x as http or socket server. It's very cool to use a Raspberry Pi with JVx without Tomcat, Jetty or JBoss - it saves system resources and is cool :)

It's now possible to use JavaScript, Python, Ruby or Groovy as client technology together with vert.x and JVx. Use the power of JVx for your preferred client technology.

The EventBus is a powerful feature to enrich your rich applications :)

Our integration project is open source and free for everyone!

New project: embedded NFC

The source code for NFC reading/writing (mifare cards, chip PN532) is available.

See http://sourceforge.net/projects/enfc.

If you use Eclipse, simply check out and open the included project. It should work without problems. A build.xml for ant is included and creates an enfc.jar under <project>/build/install/.

How to use the library?

First, test if your hardware works. Start the JUnit test cases:

<TestNFC>.testDiagnose
<TestNFC>.testCommunication

Both should be green.

If you have problems, check if your authentication Key is 0xFF_FF_FF_FF_FF_FF and change the port for the serial interface (default: COM6). Add the system property "-Dserialport=xxx" to your launch configuration or change AbstractNFCTest.

The library has one very important class and one important class :)

  • The very important class is NFC. It handles the communication with your hardware (supports read and write operations).
  • The important class is NFCReader

The NFCReader reads two sectors (á 3 Blocks á 16bytes). The first sector contains a name (usually your first and last name). The second sector contains an authentication key (whatever). If you manage different data or want save read operations, check the source of NFCReader and create your own reader - it's easy.

Before you can read data, you have to write data to your card. Use following test case to write data:

<TestNFC>.testWrite

but don't forget to change the username and auth key. The defaults are René Jahn and 010203 ;-)

A simple test application:

public static void main(String[] pArgs)
{
  nfcr = new NFCReader();
  nfcr.setPort(System.getProperty("serialport"));
  nfcr.setAuthenticationKey(new byte[] {(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF});
  nfcr.addListener(new INFCListener()
  {
    public void nearFieldCommunication(final NFCEvent pEvent)
    {
      switch (pEvent.getType())
      {
        case BlockRead:
                byte[] byData = new byte[48];
                                                       
                List<?> liBytes = (List<?>)pEvent.getObject();
                                                       
                for (int i = 0; i < 3; i++)
                {
                  System.arraycopy((byte[])liBytes.get(i), 0, byData, i * 16, 16);     
                }
                                                       
                String sName = NFC.toString(byData);

                byData = new byte[48];

                for (int i = 3, j = 0; i < 6; i++, j++)
                {
                  System.arraycopy((byte[])liBytes.get(i), 0, byData, j * 16, 16);     
                }
                                                       
                String sKey = NFC.toString(byData);
                                                       
                System.out.println("Welcome: " + sName + " [" + sKey + "]");
                break;
        case Error:
                ((Exception)pEvent.getObject()).printStackTrace();
                break;
      }
    }
  });
       
  nfcr.searchCards(false);
}

JVx, NTLMv2, Samba4 AD - authentication rocks!

Samba4 - what a great product!

My first samba PDC was version 3, and it took many nights until my old NT machines joined the samba domain... that was long time ago. As I heard of samba 4 and the big ideas (2005), I thought c'mon how would you do this? But Microsoft released important documentation about the protocol internas. And this helped!

... and some years later, we have a final release of Samba4.
Respect!

Yesterday, I read about a prebuilt samba image from SerNet (EnterpriseSamba) and thought I should try it out, because the installation was so easy! 20 minutes later, my Samba4 VM was up and running.

My first test with Windows XP as client was successful and today I added Vista, Win7 and Win8 to my new domain.
It was too easy :(

Of course, I had a problem with name resolving. The client machines should use the Samba4 server as primary DNS. I didn't change my DNS server but set the primary DNS on every machine/VM.

After my virtual domain environment was setup, I made tests with JVx' NTLM authentication. We added NTLMv1 support in 2008 or earlier - not sure when. We used jCIFS - what else.

We support authentication with signed, unsigned Applets (YES - Applets) and Desktop applications. It is one of the most important features for our business customers: Single Sign-On.

Our problems with the implementation were the difference between OS versions and Java versions. In Windows XP, NTLMv1 was default. Since Vista, NTLMv2 is default. Java 1.5 and newer support NTLM authentication via http automatically. Since 1.6 update ?? the authentication implementation is not so nice as it was before...

My tests with 1.5 and 1.6 <= 20 on WinXP, Vista, Win7, Win8 were successful. With 1.6 u38 and 1.7 u10 we have to use a new authentication dialog (be careful - German):

Authentication dialog

Authentication dialog

I'm not sure if this dialog is good or not, because NTLM authentication worked with e.g. 1.6 u20 without this thing. I didn't find a property to bypass this dialog. But if you check "save", the dialog does not pop up again (not perfect but our business users can handle it).

At the end of the day, we have a working solution for automatic NTLMv1 + NTLMv2 authentication for JVx with support for WinXP, Vista, Win7, Win8 and jre 1.5 up to 1.7. Thanks to samba4, an ActiveDirectory costs nothing.

It's a nice present :)

Welcome RaspberryPi

I ordered a Raspberry Pi model B two month ago from RS-Components... it arrived today. It was not a problem because I had a Beagleboard for tests and JavaFX for Pi is available since yesterday.

One of my friends received a (more expensive) Pi some weeks ago and we made some tests with JBossAS 7.1 and JavaSE 7 (without JavaFX). It worked like a charm and it's cool to have a JBossAS on a Pi. But without JavaFX it was not too funny.

So, back to my Pi.

The installation was very easy: Simply read the short version of Stephen Chin or the long version.

I had some smaller problems:

  • Win32DiskImager did not work with my Laptop and the builtin card-reader, and I had no external reader
  • I didn't know the username and password for login

I solved the first problem with flashnul:

flashnul 2 -L 2012-12-16-wheezy-raspbian.img

My first attempt didn't work - Raspberry Pi didn't boot (no flashing lights on my Pi - only PWR, screen was black) .... Wrote the image once again and removed the device cleanly from my Laptop - worked.

The second problem was not really a problem, but I had no idea. Used pi as username and raspberry as password (see here)

First actions after boot and setup:

apt-get update
apt-get install librxtx-java mc locate

Pi is up and running, but the image is not comparable with my Angstrom image. Some modules/drivers are missing... but that's not too important now.

My Time tracking software works on my Pi without problems. Startup time is a little bit longer as on my Beagleboard.

The next steps are some performance tests...

But Pi is definitely a MUST have.
Order your own one asap and enter the world of embedded systems with JavaFX.