Argot. Building a language for Arduinos.

Arduino MQTT Argot Blink Tutorial

arduino-mqtt-argot-blink-1.0.zip

This tutorial provides a very basic demonstration of developing a simple binary protocol to communicate with an Arduino using MQTT. It builds on the Arduino Argot Blink demo and demonstrates a few more features.

Note: A lot of Arduino's use Pin 13 to drive a LED which is great for the Blink demo. Interestingly, many Arduino's use Pin 13 when connecting to a Ethernet shield. For this reason, this tutorial actually doesn't cause the LED on Pin 13 to blink. As it's a tutorial for Argot, this issue has been ignored. To summarise, this Arduino MQTT Argot Blink demo does not actually blink. :)

The tutorial uses Java for the host language. To run the example you require:

  1. To have read over the Argot quick start example. This provides some good context.
  2. An Arduino with inbuilt Ethernet or with Ethernet shield.
  3. Have installed a MQTT broker such as mosquito. You can use my Dummies guide to installing Mosquitto on OSX if you need help.
  4. Have Eclipse or other Java IDE to run the software.

To download and setup the project in eclipse, do the following:

  1. Download the file arduino-mqtt-argot-blink-1.0.zip.
  2. Extract the zip file into your Arduino directory.
  3. In Eclipse select File->Import.
  4. Select "General->Existing Projects into Workspace".
  5. Select "Select root directory" and browse to the directory in your Arduino folder.
  6. Select finish.

To run the example, first open the ArgotMqttBlink.ino file in Arduino and upload it onto your Arduino. Next, in Eclipse run the StartHere class as a Java Application.

The Argot Blink Protocol

In the previous blink demo a simplistic 5-byte packet structure was used. In this example a more flexible design is being used.

cluster blink;

definition blink.set_delay_on 1.0:
{
	@milliseconds #uint16;
};

definition blink.set_delay_off 1.0:
{
	@milliseconds #uint16;
};

definition blink.set_delay 1.0:
{
	@ms_on 		#uint16;
	@ms_off 	#uint16;
};

definition blink.command 1.0:
	(meta.abstract [
		(meta.abstract_map #blink.set_delay_on)
		(meta.abstract_map #blink.set_delay_off)
		(meta.abstract_map #blink.set_delay)
	]);

This updated Argot definition file has three commands.

A new concept introduced in this demo is the use of the meta.abstract definition. This meta type is used to define a type where their is a choice between multiple data types.

When an abstract data type is marshalled to a buffer, it looks like:

		-----+-----------+-----------------+------
		     | uvint28   |      data       |
		-----+-----------+-----------------+------
		       identifier     selected type

The identifiers in Argot are generated dynamically and are capable of being negotiated in realtime between peers. In this demo we are using a static set of identifiers. An example message using this new Argot language would be:

		-----+-------+--------+--------+------
		     |   3   |      500        |
		-----+-------+--------+--------+------
		      uvint28   blink.set_delay_on (uint16)

The length of the above message is 3 bytes. The first byte is the blink.set_delay_on type identifier. Following this is the sequence for blink.set_delay_on which is 2 bytes.

The Java Host

With the packet structure defined, the next step is to create the classes in Java. For this I'm using the Argot Annotation Marshaller. The Annotation marshaller binds each component of Packet to a Java attribute. Here's an example of the SetDelayOn class which will be bound to the blink.set_delay_on type.

@ArgotMarshaller(TypeAnnotationMarshaller.class)
public class SetDelayOn 
extends BlinkCommand
{
	public static final String TYPENAME = "blink.set_delay_on";
	
	@ArgotTag("milliseconds")
	public int milliseconds;
	
	public SetDelayOn(int milliseconds)
	{
		this.milliseconds = milliseconds;
	}
	
	public SetDelayOn()
	{
		// Empty constructor required for annotation marshaller.
	}
	
}

All the commands extends the base class BlinkCommand which will be bound to the Argot type blink.command. As a base class for the type it does not include any methods. An alternative would be to use an interface with no methods.

@ArgotMarshaller(MetaMarshaller.class)
public class BlinkCommand 
{
	public static String COMMAND_TYPENAME = "blink.command";
}

Load and bind the library

In Argot, all data types are stored in a type library. With the data types defined and the object created in Java, the next step is to compile and load the type library.

typeLibrary = new TypeLibrary( );
		ArgotCompilerLoader loader = new ArgotCompilerLoader("blink.argot")
		{
			public void bind( TypeLibrary library )
			throws TypeException
			{
				library.bind( library.getTypeId(SetDelay.TYPENAME, "1.0"), SetDelay.class );
				library.bind( library.getTypeId(SetDelayOn.TYPENAME, "1.0"), SetDelayOn.class );
				library.bind( library.getTypeId(SetDelayOff.TYPENAME, "1.0"), SetDelayOff.class );
				library.bind( library.getTypeId(BlinkCommand.COMMAND_TYPENAME, "1.0"),  BlinkCommand.class);
			}
		};
		typeLibrary.loadLibrary(loader);

Publish commands to the Arduino

In this example the messages are being sent using MQTT. Publishing a command to MQTT is a matter of writing the message to a byte buffer and then sending the data using MQTT. As the message is using the abstract type it's a simple to write any commands to the message buffer.

	private void publishCommand(BlinkCommand command) 
	throws TypeException, IOException, MqttPersistenceException, MqttException
	{
		// Prepare the stream.
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		TypeOutputStream typeOut = new TypeOutputStream( out, typeMap );

		// Write message to stream.
		typeOut.writeObject(BlinkCommand.COMMAND_TYPENAME, command);
		out.close();
		
		// Publish message
		MqttMessage message = new MqttMessage(out.toByteArray());
		message.setQos(1);
		client.publish(MQTT_PUBLISH_TOPIC, message);
	}

The Arduino Code

In this example the implementation of the receiver is based around passing the abstract type blink.command. The processCommand reads a uint8 to get the command. Technically this should be a uvint28 (unsigned variable length 28-bit max value), however as only a small number of identifiers are being used a uint8 can be safely used.

// Process the command after receiving the complete packet.
void processCommand()
{
  Serial.println("Arduino: Process command message");
  uint8_t command = read_u8();
  
  if (command == BLINK_SET_DELAY_ON)
  {
    processSetDelayOn();
  }
  else if (command == BLINK_SET_DELAY_OFF)
  {
    processSetDelayOff();
  }
  else if (command == BLINK_SET_DELAY)
  {
    processSetDelay();
  }
  else
  {
    Serial.println("Arduino: Command not recognised");
  }
}

The example also uses the output from the Argot Micro Compiler Generator to create the blink_mqtt_dictionary.h and blink_mqtt_dictionary.h. In this example only the header file is required. Future demos will use the full dictionary. The header file provides the identifiers for the type identifiers.

#define __BASE__ 0
#define BLINK 1
#define BLINK_SET_DELAY_ON 2
#define BLINK_SET_DELAY_OFF 3
#define BLINK_SET_DELAY 4
#define BLINK_COMMAND 5
#define UINT16 6
#define UVINT28 7

The Output

The Java host shows the following output on the console.

Loading file: common.dictionary
Sending SetDelayOn(500) message
Buffer contents: [2,1,244]
Sleep 5 seconds
Sending SetDelayOff(500) message
Buffer contents: [3,1,244]
Sleep 5 seconds
Sending SetDelay(1000,1000) message
Buffer contents: [4,3,232,3,232]
Sleep 5 seconds
disconnected

The Arduino is using the Serial link to provide messages regarding the MQTT messages it is receiving and processing. The output should look like:

Arduino: Argot MQTT Blink service started.
Arduino: Received message
Arduino: Process command message
Arduino: Received command set delay on: 500
Arduino: Received message
Arduino: Process command message
Arduino: Received command set delay off: 500
Arduino: Received message
Arduino: Process command message
Arduino: Received command set delay, on: 1000 off: 1000

Conclusion

This demo shows how Argot can be used to simplify the development of protocols communicating to Arduinos. Additional features of Argot will be introduced in future tutorials. If you have any issues or queries please contact david using the email below.