We have given the knowledge-bases a new look and feel. This is intended to make finding information easier. Once within the knowledge-base, a new vertical navigation menu on the left hand side will help you find similar posts while staying within that knowledge-base section. For every post, headers distinguish different sections on the right hand side of the page, allowing readers to jump to ones that they are interested in. Topics in each section focus on specific features that each Knowledge base highlights. There are 5 different Knowledge Bases that were created based off the amount of content on our site pertaining to an application or use for the JNIOR. Here is a brief overview of each knowledge base.

General Knowledge Base

The General Knowledge Base focuses on providing posts that explain configuring and using the JNIOR Web UI and Support Tool, the hardware capabilities of the JNIOR, and steps that can be taken to troubleshoot when things don’t work. This Knowledge Base is where general questions about the JNIOR can be solved.

Tasker Knowledge Base

The Tasker Knowledge Base contains posts going over specific features of the Tasker application. It explains creating and managing workspaces, setting up connections to different devices through Tasker, and setting up Triggers and Schedules to activate tasks in Tasker.

Cinema Knowledge Base

The Cinema Knowledge Based contains posts over specific features of the Cinema application. It can explain how to create and execute macros, setup the Preshow and Cinema Server Clients, and how to troubleshoot connections made to the Cinema application.

DMX Knowledge Base

The DMX Knowledge Based contains posts over specific features of the DMX application. It can explain how to create triggers, scripts, and fixtures, how to potentially use a JNIOR 410 as a DMX controller, and how to use the JNIOR as a DMX fixture itself.

Embedded Programming Knowledge Base

The Embedded Programming Knowledge Base contains a wide variety of coding examples to create applications that run on the JNIOR. Here the JANOS runtime library can be downloaded and used in projects. Each section contains examples of short applications that can show how to do certain functionality on the JNIOR.

What is the tail command?

The tail command is used to display the last n lines of a specified file.  By default the tail command displays the last 10 lines of a file.  This can be changed by using the -n argument and specifying a new value.  If the specified file does not contain at least n lines then a the .bak version of the file will be prepended, if it exists.

Another powerful feature of the tail command is its ability to monitor and display file changes in real-time.  The specified file in monitored for changes once a second and only the changed portion of the file is displayed.

How to Install tail

Below is an update project you can apply to your JNIOR to get the tail application.

Name Version Release Date Size MD5
Tail Command v1.0 Feb 20 2023 3.5 KB e0ce27e20c337000d8fd403c76b7ce80

Usage

tail [OPTION]... [FILE]...
Short OptionsLong OptionOption ValueDescription
-n–linesNUMBERThe number of lines that should be displayed from the end of the file
-f–followMonitor the file in real-time

Default Usage

The default usage will show the last 10 lines of the specified file.

Specify number of lines to show

We can use the -n or --lines option to specify 20 lines.

Update the file in real-time

Use -f or --follow to follow the file in real-time.  New entries will be displayed.  This command will not return to the prompt until ANY key is pressed.

The JNIOR 410 is capable of handling RS-485. To do this you need to wire it correctly.

While RS-485 is commonly referred to as 2 wire, it really should include a third wire for ground. You can get away with 2 wires as long as there is a common ground between all devices. This is hard to guarantee, especially on long runs. Including the third wire is always a good idea.

RS-485 should also include termination resistors at the end of the bus. This helps prevent reflection on the wire from corrupting the communications.

Here is an article from TI on Ten Ways to Bulletproof RS-485 Interfaces.

2 wire

Again, while referred to as 2 wire, a ground wire is good practice.  In this wiring scenario D- will be landed on pin 3 and a small jumper wire will be used to connect pin 3 to pin 2.  D+ will be landed on pin 7 or pin 8 and a small jumper wire will be used to connect pin 7 to pin 8.

        Signal         DB-9
--------------------  ------
Signal Ground (GND)      5
Data (D-)                2, 3
Data (D+)                7, 8

4 wire

While referred to as 4 wire, a ground wire is good practice.

        Signal         DB-9
--------------------  ------
Signal Ground (GND)      5
RS485 TX-                2
RS485 RX-                3
RS485 RX+                7
RS485 TX+                8

DB9 Breakout Connector

You can make wiring of the DB9 connector easier by obtaining a breakout board like this one from Amazon.

Here is an example of wires landing on pins 7 and 8 with a small jumper wire.

RS485 to RS232 converter

Use an RS485 to RS232 converter and let the JNIOR handle the RS232 data.  This will enable 412 and 414 JNIORs to handle RS485.

DMX requires RS485 communication at 500K baud.  The JNIOR 412 DMX handles this inherently.  The JNIOR 410 has the ability to handle RS485.  An additional application must be loaded to get the DMX data to be streamed out the AUX port.  You can read about using the JNIOR 410 and a 412 DMX Alternative.  The downside of this is that there is additional overhead on the JNIOR and that the AUX port is not properly isolated.  In most cases the lack of isolation is not an issue but it could be given certain circumstances.

At the time of writing this article, in 2022, we have found it hard to acquire the components needed to build the 412DMX unit due to supply chain issues and chip shortages.

While using the 410 as a DMX alternative would work, some people like the IO mix on the 412.  So we decided to look at what it would take to use the 412 as a DMX alternative.  It turns out that an RS232 to RS485 adapter with a NULL modem will do the trick.  Here are links to the components that we tested an commanded DMX fixtures with here in the office.

DTECH RS232 to RS485 / RS422 Serial Communication Data Converter Adapter Mini-Size

DB9 Null Modem Adapter Male to Male

View on GitHub

The PowerEventLog application uses an immutable array to keep track of when the JNIOR turns on and off. It takes the values in an immutable array and stores them in a log file called powereventlog.

The application starts by checking if another instance of  itself is already running. If there is one already running, the instance of it trying to launch terminates itself. After checking that, it then gets the time that the application started on the JNIOR. The Immutable block is then returned (or created if it doesn’t exist yet.) to hold/retrieve the values of when the JNIOR last turned off and when it booted up again. The stop and start times of the JNIOR are re-formatted as date strings to be more readable. The log files being created are then checked to see if a backup needs to be created. Lastly, the stop and start times of the JNIOR are written to the log file, and then the times are updated for the next time the JNIOR turns off.

View on GitHub

JBakup is an application that is running on the JNIOR to help extend the life of your log files.  It does this by monitoring the filesystem for the creating of a .log.bak file.  This logic runs just once every 15 minutes.  When a .log.bak file is found that has NOT been previously processed then it is added to the .zip of the same name in the flash/baks directory.

The JAVA application doesnt take care of the zipping of the backup file data but rather creates a script that the OS executes using the ARC command.

The code is small and should be easy to follow.

After configuring the JNIOR properly, a way to send an email from it is to use the MailComposer class. This function has the user define the email being sent by building different parts of the email (Email address being sent to, Attachments to add, anyone that needs CC’d, subject, message, etc). Once these are all defined, you can use the MailComposer’s send() function to submit the email.

package emailexample;

import com.integpg.system.JANOS;
import com.integpg.system.MailComposer;

public class EmailExample {

    public static MailComposer mail = new MailComposer();
    
    public static void main(String[] args) {
        
        mail.setToAddress("YOUR EMAIL HERE");
        mail.setSubject("MailComposer Test");
        mail.setMessage("This was built and sent using the MailComposer Class.");
        mail.send();
        
    }
    
}

I put the built jar file of this example application into the JNIOR’s flash folder and ran it from the Web UI’s console tab. After it had successfully run, I checked my email and received one from the MailComposer example.

After configuring the JNIOR properly, a way to send an email from it is to use the JANOS.sendmail() function. The .sendmail() function needs the name of a mail profile on the JNIOR that you defined earlier, the subject of the email, and the email’s message.

package emailexample;

import com.integpg.system.JANOS;
import com.integpg.system.MailComposer;

public class EmailExample {

    public static MailComposer mail = new MailComposer();
    
    public static void main(String[] args) {
        
        JANOS.sendMail("YOUR EMAIL-PROFILE HERE", "EmailExample", "This was built and sent from the JANOS class.");

    }
    
}

I put the built jar file of this example application into the JNIOR’s flash folder and ran it from the Web UI’s console tab. After it has successfully run, I check my email and have received one from the JANOS.sendmail() example.

The 410 has 8 inputs and 8 outputs, the 412 and 412DMX have 4 inputs and 12 outputs, and the 414 has 12 inputs and 4 outputs. Each digital input can accept AC or DC voltage sources in the 0 – 30 V range. The input voltage must be greater than 2 VDC for the input to register as “on” and then less than 1 VDC to register as “off”. The JNIOR uses a 2-piece terminal connector system for all power and I/O wiring connections allowing for easy installation and/or removal of the JNIOR. Digital Inputs are Optically Isolated.  

Controlling Digital Inputs

When controlling the JNIOR’s I/O, the JANOS class can be used to get/manipulate their statuses. In the following example the JANOS class is used to invert an input and print the input state mask, manipulate an input counter, and check an input’s usage meter.

View on GitHub

I put the built jar file of this example application into the JNIOR’s flash folder and ran it from the Web UI’s console tab. As you can see it displays different data about the inputs at the time of the application running.

Getting Inputs from the IO Log

Another way to interact with the I/O on the JNIOR is via the Iolog Monitor. The Iolog Monitor is an object that can be checked for I/O events that have occurred on the JNIOR. There is the IoEvent class and Iolog class. An IoEvent is when an input or output state changed on the JNIOR, and the Iolog is an object that contains all the IoEvents from a certain timestamp. The example below inverts an input, and then shows how the Iolog has recorded that input pulse as an IoEvent.

View on GitHub

I put the built jar file of this example application into the JNIOR’s flash folder and ran it from the Web UI’s console tab. As you can see it recorded the input change where input 1 turned on and again when it turned back off.

When creating an application, being able to send emails from it may be something a User wants to do. JNIORs have email blocks in their configuration that can be setup to send emails.

Setting Up JNIOR Email

To properly setup an email for the JNIOR to use, you’ll want to use the JNIOR’s Web UI and navigate to the Email Account section under Configuration. Here you’ll want to include the Mail Server, From Address, and SMTP Username your JNIOR will use to send the email. These are required in order to send emails from the JNIOR.

Next, in the Network section you’ll want to make sure you have a DNS Address declared. For our examples we use 8.8.8.8, which is Google’s.

Lastly, we’ll want to make sure we give the address we are sending to to the Mail-Profiles section. Only a ToAddress is needed, but additional information can be entered to be used as a default. This is used for the JANOS.sendmail() class.

Now that this is setup, we can now create an application that can use these settings to send an email. The following example shows two different ways that an email can be sent from an application. The first way uses the JANOS class, and the other uses the MailComposer class.

View on GitHub

I put the built jar file of this example application into the JNIOR’s flash folder and ran it from the Web UI’s console tab. Once its run an email should be sent to the address, subject, and message you declared.

Watchdog

The concept of using a watchdog is to ensure that the application continues to run as expected.  JANOS provides a Watchdog class that has a couple of options.  A sample of how to use that class can be found here.

Single Instance

Most times we only want one instance of an application running at a given time.  Use the JANOS.registerProcess() method to check to make sure there is not another instance running. Here is an example of using the registerProcess() method.

String applicationName = "TestApp";
if (1 < JANOS.registerProcess(applicationName)) {
    JANOS.syslog("Another instance of " + applicationName + " is running");
    System.exit(-1);
}

Versioning

A great way to be certain that specific code is running is to implement versioning.  If the application is going to be released or there are going to be multiple releases then versioning is nearly a must.  Many times versioning takes the form of major.minor.build.  This is not always the case. Sometimes you will see version numbers that start with the year that it was released.  For example, Ubuntu uses year.month to get 22.04.  The format you use is completely up to you.

Model and I/O Count

One issue that your application can have is handling the different models of JNIORs and the differing input and output count.  The following code can help you with that.

    /**
     * @return the number of inputs based on the model of jnior
     */
    public static int getInputCount() {
        // if a 412 or 412 DMX then return 4.  If not then check if a 414 and return 12.  If not 
        // then return 8.
        String modelString = JANOS.getRegistryString("$Model", "");
        return (modelString.startsWith("412")) ? 4 : (modelString.equals("414")) ? 12 : 8;
    }



    /**
     * @return the number of outputs based on the model of jnior
     */
    public static int getOutputCount() {
        // if a 412 or 412 DMX then return 12.  If not then check if a 414 and return 4.  If not 
        // then return 8.
        String modelString = JANOS.getRegistryString("$Model", "");
        return (modelString.startsWith("412")) ? 12 : (modelString.equals("414")) ? 4 : 8;
    }

Loading an Application

We recommend that all applications are saved in the /flash directory.  There are multiple ways to upload a file to the JNIOR.  How you decide to do that is up to you but the WebUI is a great tool for accomplishing this task.

Open the WebUI and go to the Folders tab.  Click on the /flash directory in the tree view on the left.  You can now drag and drop your JAR file to the view on the right.

Once you drop the file you will see the transfer progress bar.

Great, the application is on the JNIOR. We now need to decide how and when it should be executed.

Running the Application in the Foreground

When should we run an application in the foreground?

Answer, when we are developing, debugging or when an application needs to interact with the user from a command prompt. Notice I said from a command prompt. There are other ways to interact with the user. For example, a web interface. But that will be discussed later.

To execute an application from the command line we can enter java APPLICATION_NAME.jar or simply APPLICATION_NAME. if only the application name is entered then JANOS will look for a JAR file. If the file is found then it is executed.

Running the Application in the Background

When would we want to execute an application in the background?

Answer, when we have an application that we are running that we will not interact with but we still want to be able to interact with the command line.  To do this we will append a “&” to the end of the command we use to launch the application.  The command line prompt will be returned immediately. 

Setting an Application to Run on Boot

When do we want to execute an application on boot?

Answer, when we have a production application that should always be running.  To set this up we will make a run/ registry key.  The name of the registry key can be anything you want.  The content of the key is the way that you would execute the program from the command line as we did above.  This is the same as executing an application in the background but without the user having to start the application manually.

Next > Other Application Considerations

Series 4 JNIOR’s have a file directory that can be interacted with via a command line connection or from the Web UI. Being able to interact with the file directory and read/write files to it can be a useful tool when creating applications, from recording versioning numbers to writing data to reference later. Below is a small example below that writes and then reads to a file.

Directories and File Interaction

To start a file object is declared with the directory of the temp folder and the name of the file we are creating which is “test.log”. We also create another file object called directory and we are going to use this to display all the files located under the flash directory in the JNIOR by. We get the files in the flash directory by assigning the value ‘/flash’ to it, and then using the .list() function we can return a string array of all the files under that directory. We declare a local string array called files and populate it with the file names we just got. Then we go through and print out the name of each one. After this we declare a BufferedWriter to create a FileWriter. The FileWriter is then used to write a string to the test.log file we just declared. Next a BufferedReader is declared to create a FileReader. The FileReader is used to the read whatever data is on the file as a string, and since we just wrote to it, it will print out what we’ve writer to the file.

View on GitHub

Filing Example

I put the built jar file of this example application into the JNIOR’s flash folder and ran it from the Web UI’s console tab. As you can see it, application runs and prints out the text that was written to the file. You can also see the test.log file is created in the temp folder.

You can easily pulse an output using Tasker.  From an open Workspace you will click + Add Action… to get the Add Action dialog.  From there you will select Pulse Relay (channel, duration).

Once the action has been added you will need to configure the correct channel and duration.

The JANOS Runtime Library should be installed as a Library in your IDE.  Here is how to do that in the Apache NetBeans IDE.

Open Libraries Dialog

Open the IDE and select Libraries from the Tools menu.

Create New Library

Click New Library…

Give the Library a name. We suggest JanosRuntime_2.0

Add JAR to Library

On the right side of the dialog you will new click Add JAR/Folder…

Navigate and select the location where the Janos Runtime JAR file was saved.

Adding in the sources

Now that the JanosRuntime library has been created, we want to add the sources so that we can reference them while working with our code.  We do not distribute source code but the method stubs are still extremely helpful.

To do this we will click on the Sources tab and then repeat the steps to Add JAR/Folder as you did when creating the library.

Add Javadoc

Adding the javadoc will enable the NetBeans intellisense. To do this we will click on the Javadoc tab and then repeat the steps to Add JAR/Folder as you did when creating the library.

Next > Creating a Project

The registry on the JNIOR is what defines how it is configured. Registry keys hold information that persist past reboots, allowing applications to set them and save settings that have been created. This information can be connection settings, device identification, versioning, etc. Below is a quick example that prints out a specific registry key’s information, and then prompts the user to enter a new value for it. 

In this example the registry key being referenced on the JNIOR called AppData/RegistyTest. This registry key doesn’t exist the first time the application is run, and it will print out “Registry not created yet”. It will then prompt the user to enter a value for it, and once that’s done it will exit the application. Running the application a second time will show that the value entered for the registry key will now be what’s displayed for its value.

View on GitHub

I put the built jar file of this example application into the JNIOR’s flash folder and ran it from the Web UI’s console tab. As you can see it, the registry key report empty the first the application is run, and the second time its run the registry key contains the value enter for it the first time it was run.

Here shows the registry key we created in the Registry Tab of the JNIOR Web UI.

So you’re looking to write your own code to run on the JNIOR? You have come to the right place. Writing code for the JNIOR is as easy as writing code for your PC. The JNIOR will run the JAR that is created by your favorite IDE. There are almost limitless possibilities when it comes to what you can program on the JNIOR. Most of the applications that we have written have come from customer requests over the years.

This section of our website is not meant to teach you how to code but rather to show you how to enable your IDE to write JNIOR code that is targeted for the JNIOR.

Note: Additional Libraries cannot be used with JNIOR applications.

Prerequisites

  • Java JDK
  • Java IDE (We use Apache NetBeans)
  • JANOS Runtime Library
  • Understanding of Java Programming

Check for Java

Type java -version at a Command Prompt

JANOS Runtime Library

Applications targeted to run under JANOS must be built against the JANOS Class Library. This library can be found in the etc/ folder on your JNIOR Model 410. This file is OS version dependent although it is likely not to change dramatically from release to release. You might note the date and before you update or finish an application for your JNIOR make sure that you are using the latest version that you have available. INTEG can also send you a copy of JanosClasses.jar on request.

The JANOS Runtime Library does not contain the full JVM that you might be used to programming against. It is close but to save code space we have omitted some classes and methods. Take a look at the JANOS Runtime Javadoc to see what classes and methods are available.

Name Version Release Date Size MD5
JanosRuntime.JAR v2.5 Jun 04 2024 1.6 MB 9ee359c454dd0776a687242aee01f94e

Next > JANOS Runtime Installation

There could be a want for an application that performs different functionality, completing multiple operations at the same time. The JNIOR accomplishes this with threading. A thread is a sequence of instructions within a program that can be executed independently of other code. The JNIOR is able to handle threading via the default JAVA library. Below are two quick examples of threading, with one of them using synchronization. 

Non-Synchronized Threading

In this first example, there is a main method that creates two threads, each supplying it an array of words that will be used to create sentences and print them out. Each new thread calls a function called slowStringBuffer, taking the words in their string array’s they’ve been supplied and adding them to the string buffer in that function. Since the threads run at the same time, they add their words to the string buffer simultaneously. This results in nonsense being printed out for the sentences, showing that synchronization in our next example is useful in avoiding this issue.

View on GitHub

I put the built jar file of this example application into the JNIOR’s flash folder and ran it from the Web UI’s console tab. As you can see it, the threads compete against each other to build their sentences, resulting in nonsense being printed out.

Synchronized Threading

In this second example, the only change that is made is that the slowStringBuffer function is made synchronized. This results in one thread taking control first, making sure it prints out its sentence completely before the next thread can start its sentence. This results in two complete sentences being generated.

View on GitHub

I put the built jar file of this example application into the JNIOR’s flash folder and ran it from the Web UI’s console tab. In this example two complete sentences are formed and printed.

On every JNIOR, there is a System Message Pump that is constantly circulating any message sent between applications. Each message sent around the system has a unique type that identifies the message. This is done so when an application receives a message, it can determine if the message was meant for it. If the message was for that application, it consumes the message and reacts accordingly for the what the application is doing. If its not meant for it, then it simply re-broadcasts the message so the next application can evaluate the message until the correct application receives it. 

Message Types

As far as the different types of messages that can be sent, there are two groups. The first group is the system messages, which are predefined and reserved only for the OS to use when its performing checks and tasks. Message numbers below 1024 (0x400) are reserved for the system. The most common example of this is the SM_PROBE (0x02) message. This is a message that isn’t supposed to be consumed by other applications and is supposed to make its way back to the OS after its sent. If the message doesn’t come back, then it knows somethings wrong, and an application is consuming messages it shouldn’t be. It fixes this by restarting the OS. Here are other predefined system examples the JNIOR OS uses. The other group of messages are user defined messages. These messages can have any message number at or above 1024 (0x400), and can be given any message a user would wish to define for the message. 

Message Example

Below is an example of two applications communicating with one another using a user defined message. They use the System class to declare a MessagePump and SystemMsg objects. The first application has a separate class that declares a listener interface that will be used to grab messages when they enter the message pump. Inside the first application, it opens the message pump and permanently loops, only pausing the loop when its listening for a message. When it receives a message with type 1600 it prints the string in the message and continues the loop again. 

View on GitHub
View on GitHub

The second application opens the message pump, sends a user defined message containing a string and the message number 1600, and then closes the pump.

View on GitHub

I put the built jar files of these example applications into the JNIOR’s flash folder and ran one from from the Web UI’s console tab and the other from a command line connection. As shown below, one application constantly loops through itself, pausing when its trying to get a message from the message pump and then printing the message out when it does. The other sends the message the first one is listening for.

NOTE: In the picture above, the message only prints out once, while other times it just goes through the loop without printing the message. This is because we only handle one type of message, 1600. If it continues through the loop without printing a message, it means it got a message with a number type that wasn’t 1600. The other message its getting is most likely the SM_PROBE (0x02) message.

Many times we write an application that should be the only instance of that application running.  That application may monitor inputs, control outputs, send email, or perform logic.  Whatever that application is doing, it should be the only one doing that particular thing at any given time.

The ensure that this happens we use the JANOS.registerProcess(id) method.  This method returns the number of processes that have been registered with that given id.  That id can be any unique identifier given to that application.  It can be a name or a random UUID.

If the registerProcess() method returns a value greater than one then we will exit our application.  This will leave the first instance running.  Here is an example.

        // make sure there is only 1 instance of this application running
        if (1 < JANOS.registerProcess(Application.getAppName())) {
            JANOS.syslog("Another instance of " + Application.getAppName() + " is running");
        }