Serial Port

Using serial port

A serial port interface at 3.3 volt is available on the CM3-Home to connect external microcontrollers like Arduino or ESP8266.

The signals are available on screw terminals as visible below and are at 3.3 volt level. The lines are not-tolerant to 5 volt.

This port is visible in Linux as /dev/ttyUSB3 device.

Example

As an example of a serial communication, a working example of data exchange with an Arduino board is supplied in the SD card.

To show how informations can be exchanged between CM3-Home and Arduino board in both directions using different items, we used some devices commonly used in this environment:

  • NeoPixel Ring
  • A mini servo
  • A Cadmium Sulfide (CdS) LDR (Light Dependent Resistor) or photoresistor

    The LEDs color and position and the servo angle can be set with the ready to use interfaces. The ambient light level is shown with a knob used as instrument.

Classic UI

Basic UI

Hab Panel

Serial binding configuration

Control and Arduino board through the serial port.

Let’s see the Arduino code. The serial port, configured accordingly to the Arduino board used, keeps waiting for data. When they are available, the program starts decoding them as a sequence of comma delimited BCD values. The string ends when a carriage return character is received.

The sketch uses some standard libraries:

  • Fastled library available in Arduino environment. In OpenHAB we used a Colorwheel item with 0 to 255 RGB values and the number of LEDs to light up from 1 to 16 (0 = all OFF)
  • Servo library. It receives from OpenHAB the position command from 0 to 180° to set the servo position
void ReadCommand(void)
{
/*Read a command string from the serial port
the string must follow this format:
LedNum,red,green,blue,servo1Pos\r
where:
LedNum is the number of LEDs ON on the LED ring (clockwise), 0 (all OFF) to 16 (all ON)
red, green blue are the RGB values for all the LEDs, 0 to 255
Servo1Pos is the position of the servo, 0 to 180°
all the values are in BCD no leading zeroes, i.e.:
value = 128 means
ASCII 49
ASCII 50
ASCII 56
value = 64 means
ASCII 54
ASCII 52
all the values are comma separated
all values must be always sent, even if no change
carriage return terminates the string
*/

while (Serial1.available() > 0) 
{
   digitalWrite(led,1);
   pixel = Serial1.parseInt();
   red = Serial1.parseInt();
   green = Serial1.parseInt();
   blue = Serial1.parseInt();
   servo1Pos = Serial1.parseInt();

   if (Serial1.read() == '\r') 
   {
      digitalWrite(led,0);
      pixel = constrain(pixel, 0, 16);
      red = constrain(red, 0, 255);
      green = constrain(green, 0, 255);
      blue = constrain(blue, 0, 255);
      servo1Pos = constrain(servo1Pos, 9, 180);

      gear(pixel, red, green, blue);

      servo1.write(servo1Pos);
   }
 }
}

The LED ring and the servo are driven with the received values

void gear(int Pos, byte red, byte green, byte blue)
{
   if (Pos>NUM_LEDS[0])
   {
      Pos=NUM_LEDS[0];
   }

   for(int i=1; i<=NUM_LEDS[0]; i++)
   {
      int j=NUM_LEDS[0]-i;
      if(i<=Pos)
      {
         setPixel(j,red,green,blue);
      }
   else
   {
      setPixel(j,0,0,0);
   }
  }
FastLED.show();
}

The communication is performed through the Serial Binding. The port to use must be added to the java environment (in this case /dev/ttyUSB3) in /etc/defaults/openhab2

EXTRA_JAVA_OPTS="-Dgnu.io.rxtx.SerialPorts=/dev/ttyUSB0:/dev/ttyUSB2:/dev/ttyUSB3:/dev/ttyS0:/dev/ttyS2:/dev/ttyACM0:/dev/ttyAMA0"

Then configure the items needed:

String Arduino "Light [%d]"  (arduino) {serial="/dev/ttyUSB3@9600"}

Dimmer LedRingPos "LED Ring"  (arduino)
Color LedRingColor "Color [%s]"  (arduino)

Dimmer Servo1 "Servo"  (arduino)

String toSerialTTL "LED Ring [%s]"  {serial="/dev/ttyUSB3@9600"}
  • The ‘Arduino’ item is used to receive the ambient light data string from the external board.
  • The ‘LedRingPos’ is used to send the number of LEDs in the ring to switch on.
  • The ‘LedRingColor’ item is a Color type, specific to manage HSB color values.
  • The ‘Servo1’ item is a dimmer type to setup the servo position.
  • The ‘toSerialTTL’ item is not visualized, it’s used to send the string to Arduino through the serial port.

To prepare the data from and to the external board, we have to use some rules.

When the colorwheel values change, the LedRingColor item status acquires the HSB variable values. Because the LED ring needs the 0 to 255 RGB values, we must use the red, green, blue (from 0 to 100) methods multiplied by 255. They must then formatted as a BCD comma delimited string and sent to the serial port.

var HSBType hsb
var RingPos = 0.0
var red = 0
var green = 0
var blue = 0
var Servo1Pos = 0.0

rule "HSBtoRGB"
when
Item LedRingColor changed
then
hsb = LedRingColor.state as HSBType
red = (hsb.red * 2.55).intValue
green = (hsb.green * 2.55).intValue
blue = (hsb.blue * 2.55).intValue

toSerialTTL.sendCommand(RingPos+","+red+","+green+","+blue+","+Servo1Pos+"\r")
end

To setup the number of lighted LEDs a dimmer item is used. It generates a 0 to 100 value. Dividing it by 6.25 we have a 0 to 16 value.

rule "Led Ring Pos"
when
Item LedRingPos changed
then
RingPos = ((LedRingPos.state as DecimalType) / 6.25).intValue
toSerialTTL.sendCommand(RingPos+","+red+","+green+","+blue+","+Servo1Pos+"\r")
end

Similarly the Servo1 dimmer status is multiplied by 1.8 in order to have a 0 to 180 range.

rule "Servo1 Pos"
when
Item Servo1 changed
then
Servo1Pos = ((Servo1.state as DecimalType) * 1.8).intValue
toSerialTTL.sendCommand(RingPos+","+red+","+green+","+blue+","+Servo1Pos+"\r")
end

The value received by the Arduino, i.e. the ambient light, must be converted in a numeric variable to be used. The item status must therefore be converted as a string before to have a BCD value, this can be then converted as an integer.
Being a numeric variable it can be used in a rule to, for example, switch on one of the aforementioned KMTronic relays when the value of ambient light falls below an established threshold.

rule "LDR"
when
Item Arduino changed
then
var LightStr = Arduino.state.toString
var Light = new java.math.BigDecimal(Integer::parseInt(LightStr))

      if (Light > 800)
      {
         toSerial.sendCommand("\u00FF\u0001\u0001")
      }
      else
      {
toSerial.sendCommand("\u00FF\u0001\u0000")
}
end

To use those items they must be defined in our sitemap file.

  • Text item=Arduino – shows the value read from LDR (0-1024)
  • Slider item=LedRingPos – setup the number of lighted LEDs on the ring
  • Colorpicker item=LedRingColor – setup the color and the brightness of the LEDs ring
  • Slider item=Servo1 – manage the servo position
Frame label="Serial"
{
Text label="Arduino" icon=sensor
{
Text item=Arduino
Slider item=LedRingPos
Colorpicker item=LedRingColor
Slider item=Servo1
}
}
 

TIP

Sometime it happens that the value of an item in the UI is not dynamically updated. In this case you can see in the karaf control that the PageChangeListener.get service is closed due to an undefined sitemap reading when the file has been saved. To re-establish the normal functionality you have to restart the OpenHAB service:

sudo systemctl restart openhab2
Links

Share