You are here

Smart Station with Java Embedded [Part 1]

In this post we will see how to realize a complete monitoring station of a domestic environment, for example to monitor the temperature, the gas, the movement and the possibility of storing at fixed time rate or to request a video.
It is a station that requires the management of more analog or digital channels with discrete processing performance. We will see how to make an Android  mobile application interfaced with raspberry PI 3.
To do this the architecture of our station needs the following important elements:
– An analog / digital converter to handle multichannel analog signals that raspberry can not manage to embedded level
– A web server to be installed inside the raspberry so you can manage the request-response calls from Android app

To be able to manage the communication between the sensors and the raspberry will use the SPI interface. The SPI transmission is between a device called master and one or more slaves. The master controls the bus, outputs the clock signal, decides when to start and end the call. The SPI bus is serial, synchronous to the presence of a clock that coordinates transmission and reception of the individual bits and determines the transmission speed and full-duplex because the “conversation” can be done simultaneously in transmission and reception.

 

spi

The bus is based on 4 signals:

  • SCLK – SCK: Serial Clock(from  master)
  • SDI – MISO – SOMI – DI – SO: Serial Data Input, Master Input Slave Output (input for the master and output for slave)
  • SDO – MOSI – SIMO – DO – SI: Serial Data Output, Master Output Slave Input (output from master)
  • CS – SS – nCS – nSS – STE: Chip Select, Slave Select, issued by the master to choose with which slave device wishes to communicate

Raspberry has SPI interface.

spi_rasp
The choice of an analog-digital converter is dictated by the possibility of having more channels and a SPI interface towards raspberry. We chose the MCP3008 (https://cdn-shop.adafruit.com/datasheets/MCP3008.pdf).
The Microchip MCP3008 is an eight-channel, 10-bit ADC.

The pin MCP3008

Eight channels refers to the fact that the MCP3008 has feature to process voltages on eight different inputs. These channels can be read in two different ways. The most used is called “single ended input”, where the voltage level is read between the selected voltage reference, VREF and a ground level shared in common with the circuit doing the measuring and the circuit being measured. The other capability is to read a differential input between a pair of pins, IN+ and IN-. With the differential input, you can read the voltage difference between two inputs, and even use them to clean up signal noise.

The 10-bit refers to the sampling range of the ADC itself. B0000000000 = 0 and  B1111111111 = 1023, means that it is possible to measure 1024 different voltage levels, typically between land and V REF. So if you have a 5V reference, and can split times in 1024, each step would be equivalent to a measure of 0.0049V. With reference 3V3, each step is equivalent to a measure of 0.0032V.

 

The general sequence of transmitting on mcp3008 runs like this:

  • Inform the chip to get ready to perform a measurement

According to the MCP3008 datasheet, the first bit received after the CS pin goes low is the start bit. This will tell the ADC that it needs to be ready to perform a measurement.

  • Inform the chip which single channel or differential pair to measure

First bit can be 1 for single and 0 to differential, instead the next three bits determining which channel or channels will be used for the measurement. These bits must be sent immediately after the start bit, so care must be taken to ensure that data is clocked out on MOSI in this order..

  • Give the chip time to perform the measurement.
  • Begin reading back the data of the measurement.

Once the final channel bit has been sent and the appropriate time granted to allow the ADC to do it’s thing, it will clock out a single null bit, followed by the 10 bits of sampled value, MSB First.

Of course, since this is all SPI, we also need to wrap that entire sequence inside taking the ADC CS low, running the sequence, then bringing the ADC CS high again.

mcp3008_clock

Here the connection between the MCP3008 and raspberry :

  1. MCP3008 VDD –> 3.3V
  2. MCP3008 VREF –> 3.3V
  3. MCP3008 AGND –> GND
  4. MCP3008 CLK –> SCLK
  5. MCP3008 DOUT –> MISO
  6. MCP3008 DIN –> MOSI
  7. MCP3008 CS –> CE0
  8. MCP3008 DGND –> GND

 

In this first post we will see how to manage the temperature measurement. We can use any thermistor and examine its temperature-dependent curve to process the calculation logic within our software.

IMG_20160723_160012

 

A thermistor is a type of resistor whose resistance is dependent on temperature. Thermistors are widely used as temperature sensors namely positive temperature coefficient (PTC ) and negative temperature coefficient (NTC) in accordance with the temperature coefficient. With PTC, resistance increases with the increase of temperature. While with NTC, resistance decreases with the increase of temperature.

 

We use the following configuration of our thermistor:

termistore

with R1=10Kohm. CHO is the output of the sensor and the input of our ADC.

Since ADC is a 10bit converter then  Aref=1023:

term2

From which we can derive the value of Tk as B / [ln (Rt/R0) + B/T0].

The application that is installed in the raspberry is a Java Micro Edition Embedded solution. It has a structure that works as a web server and through the possible operations required by the client via json, performs SPI commands to the sensors  via MCP3008 ADC.

platform

Here we omit the operations that are used to configure the IDE via java me sdk  and it only describes the solution as a whole. You can download Java embedded ME at the following link: http://www.oracle.com/technetwork/java/embedded/javame/embed-me/downloads/index.html

Below is the class diagram of the solution:

 

class

 

The web server application is a midlet that manage the input json requests with a specific handler JsonStationRequestHandler.

public class WebServerStationApplication extends MIDlet {

....

@Override
    public void startApp() {
        
      ....

        // Obtaining number of threads which will serve incoming requests
        int threadsNumber = getIntFromProperty(SERVING_THREADS_NUMBER_PROPERTY_NAME, SERVING_THREADS_NUMBER_DEFAULT_VALUE);
        if (threadsNumber <= 0) {
            System.out.println("Bad serving threads number: " + threadsNumber + ". Must be positive");
            destroyApp(true);
            return;
        }

        // Obtaining port to listen for incoming connections
        int listeningPort = getIntFromProperty(LISTENING_PORT_PROPERTY_NAME, LISTENING_PORT_DEFAULT_VALUE);
        if (listeningPort < 0 || listeningPort > 65535) {
            System.out.println("Listening port must be in [0,65535] range. The specified value is: " + listeningPort);
            destroyApp(true);
            return;
        }

        // Creating a web server instance
        webServer = new WebServer(listeningPort, threadsNumber);

       ...

      // Persisting connections allows to reuse connection for multiple
        // requests from the client
        boolean persistConnections = getBooleanFromProperty(PERSIST_CONNECTIONS_PROPERTY_NAME, PERSIST_CONNECTIONS_DEFAULT_VALUE);
        webServer.setPersistConnections(persistConnections);

...
// Initializing and adding handler which demonstrates JSON usage
        // (if supported)
        boolean supportsJson = getBooleanFromProperty(SUPPORTS_JSON_PROPERTY_NAME, SUPPORTS_JSON_DEFAULT_VALUE);
        if (supportsJson) {
            webServer.addRequestHandler(JSON_TEST_HANDLER_CONTEXT_PATH, new JsonStationRequestHandler());
        }

....

Below is the property permissions of the solution:

perm

The JsonStationRequestHandler is the handler that manage the sensors commands. To put and riceve bits from mcp3008 I use a custom method readMCP3008Channel() with elaboration of ByteBuffer data.
To convert value to temperatura data I use another specific and custom method convertValue() with two step of elaborations :
a) use the formula of thermistor shown above
b) use the taylor series to implement natural logarithm (because Math.log in java embedded is not available)

This is the structure of handler :

public class JsonStationRequestHandler implements RequestHandler {

...

@Override
    public HttpResponse handle(HttpRequest request, String contextPath, String relativePath) {
        // Filtering action by path which is relative to the context path
        switch (relativePath) {
...
            case "/...":
                return memo(request);
            case "/....":
                return put(request);
            case "/gettemp":
                return gettemp(request);

....

private HttpResponse gettemp(HttpRequest request) {
        // Checking that request method is POST
        if (request.getRequestMethod() != HttpRequest.POST_REQUEST_METHOD) {
            // Otherwise sending an error with allowed method included in the
            // "Allow" header
            return HttpResponse.methodNotAllowed(String.format(RESPONSE_TEMPLATE, "Error", "Method not allowed")).addHeader("Allow", "POST");
        }

        // Checking that contentType is valid
        String contentType = request.getHeaderValue(HttpResponse.CONTENT_TYPE_HEADER);
        if (contentType == null || !contentType.contains(JSON_CONTENT_TYPE)) {
            return new HttpResponse(Status.UNSUPPORTED_MEDIA_TYPE).setBody(String.format(RESPONSE_TEMPLATE, "Error", "Only application/json media type is supported"));
        }

        // Getting body as JSON and trying to parse it
        JsonBodyWrapper requestBodyAsJson = request.getRequestBodyAsJson();
        if (requestBodyAsJson != null) {

            try {

                SPIDeviceConfig config1 = new SPIDeviceConfig.Builder()
                        .setControllerNumber(0)
                        .setAddress(0)
                        .setClockFrequency(500000)
                        .setCSActiveLevel(SPIDeviceConfig.CS_ACTIVE_LOW)
                        .setWordLength(8)
                        .setBitOrdering(Device.BIG_ENDIAN)
                        .build();

                SPIDevice mcp3008 = DeviceManager.open(config1);

                int read = readMCP3008Channel(0, mcp3008);

                System.out.println("read mc3008= " + read);

                float temp = convertValue(read);

                mcp3008.close();
                
                              
                return HttpResponse.ok(Json.createObjectBuilder().add("temp", temp).build().toString()).addHeader(HttpResponse.CONTENT_TYPE_HEADER, JSON_CONTENT_TYPE);
}

....


lombamarc
I have over ten years experience in project management and software architect in complex and innovative projects for multinational ICT. I have a electronic engineer extraction with automatic specialization. For years I deal with innovation also as an active contributor to several open hardware community as Rfduino, Arduino Yun, etc ... I think that in every company there is a need to co-create ideas and innovation from every person with tools and working groups motivated and sharing and dissemination of culture at all levels. Technology and research are not enough, if there is no interaction and sharing there can be no innovation.

Leave a Reply

Top