Tutorial - Rugged Approach

With the new Protocol 2.0, it is possible to write programs that are resilient to outages, brief electricity cuts and similar things.

The general approach for such a program is shown below in pseudo code:

func enumerate_callback(...) {
    configure_brick();
    configure_bricklet();
}

func connected_callback(...) {
    ipcon.enumerate();
}

func main() {
    ipcon.enumerate();

    while (true) {
        if (brick_is_configured) {
            do_something_with_brick();
        }

        if (bricklet_is_configured) {
            do_something_with_bricklet();
        }
    }
}

Generally, you have to make sure that the configuration is done while the Bricks and Bricklets are enumerated. This ensures that the configuration (e.g. callback periods) is always there, even if a Brick or Bricklet was restarted and lost its configuration.

To do this, you can put the configuration code in the enumeration callback. You should also make sure, that a new enumeration is triggered if the TCP/IP connection was lost and then reconnected. If the connection was lost, a Brick or Bricklet might have been restarted in the meantime, so it needs to be reconfigured.

In the following you can find C# and Python source code for a program that displays the temperature on a LCD 20x4 Bricklet. This program should keep working if you reconnect/restart the Master Brick or if a Wi-Fi connection is lost. It is even possible to exchange the Temperature or LCD 20x4 Bricklet, since the program uses the UID from the enumeration.

C#

Download (ExampleRugged.cs)

  1using Tinkerforge;
  2
  3// This class will use any LCD Bricklet and Temperature Bricklet that
  4// are connected to the PC and display the temperature on the LCD.
  5//
  6// The program should stay stable if Bricks are connected/disconnected,
  7// if the Brick Daemon is restarted or if a Wi-Fi/RS485 connection is lost.
  8// It will also keep working if you exchange the Master or one of the
  9// Bricklets by a new one of the same type.
 10//
 11// If a Brick or Bricklet loses its state (e.g. callback configuration)
 12// while the connection was lost, it will automatically be reconfigured
 13// accordingly.
 14class ExampleRugged
 15{
 16    private static string HOST = "localhost";
 17    private static int PORT = 4223;
 18
 19    private static IPConnection ipcon = null;
 20    private static BrickletLCD20x4 lcd = null;
 21    private static BrickletTemperature temp = null;
 22
 23    static void Main() 
 24    {
 25        // Create IP Connection
 26        ipcon = new IPConnection();
 27
 28        // Register IP Connection callbacks
 29        ipcon.EnumerateCallback += EnumerateCB;
 30        ipcon.Connected += ConnectedCB;
 31
 32        // Connect to brickd, will trigger cb_connected
 33        ipcon.Connect(HOST, PORT); 
 34        ipcon.Enumerate();
 35
 36        System.Console.WriteLine("Press enter to exit");
 37        System.Console.ReadLine();
 38        ipcon.Disconnect();
 39    }
 40
 41    // Callback updates temperature displayed on lcd
 42    static void TemperatureCB(BrickletTemperature sender, short temperature)
 43    {
 44        if(lcd != null)
 45        {
 46            lcd.ClearDisplay();
 47            string s = "Temperature: " + temperature/100.0 + (char)0xdf + "C";
 48            lcd.WriteLine(0, 0, s);
 49        }
 50    }
 51
 52    // Callback switches lcd backlight on/off based on lcd button 0
 53    static void ButtonPressedCB(BrickletLCD20x4 sender, byte button)
 54    {
 55        if(lcd != null)
 56        {
 57            if(button == 0)
 58            {
 59                if(lcd.IsBacklightOn())
 60                {
 61                    lcd.BacklightOff();
 62                }
 63                else
 64                {
 65                    lcd.BacklightOn();
 66                }
 67            }
 68        }
 69    }
 70
 71    // Callback handles device connections and configures possibly lost
 72    // configuration of lcd and temperature callbacks, backlight etc.
 73    static void EnumerateCB(IPConnection sender, string UID, string connectedUID, 
 74                            char position, short[] hardwareVersion, 
 75                            short[] firmwareVersion, int deviceIdentifier, 
 76                            short enumerationType)
 77    {
 78        if(enumerationType == IPConnection.ENUMERATION_TYPE_CONNECTED ||
 79           enumerationType == IPConnection.ENUMERATION_TYPE_AVAILABLE)
 80        {
 81            // Enumeration is for LCD Bricklet
 82            if(deviceIdentifier == BrickletLCD20x4.DEVICE_IDENTIFIER)
 83            {
 84                // Create lcd device object
 85                lcd = new BrickletLCD20x4(UID, ipcon);
 86                lcd.ButtonPressed += ButtonPressedCB;
 87
 88                lcd.ClearDisplay();
 89                lcd.BacklightOn();
 90            }
 91            // Enumeration is for Temperature Bricklet
 92            if(deviceIdentifier == BrickletTemperature.DEVICE_IDENTIFIER)
 93            {
 94                // Create temperature device object
 95                temp = new BrickletTemperature(UID, ipcon);
 96                temp.Temperature += TemperatureCB;
 97
 98                temp.SetTemperatureCallbackPeriod(50);
 99            }
100        }
101    }
102
103    // Callback handles reconnection of IP Connection
104    static void ConnectedCB(IPConnection sender, short connectReason)
105    {
106        // Enumerate devices again. If we reconnected, the Bricks/Bricklets
107        // may have been offline and the configuration may be lost.
108        // In this case we don't care for the reason of the connection
109        ipcon.Enumerate();
110    }
111}

Python

Download (example_rugged.py)

 1#!/usr/bin/env python
 2# -*- coding: utf-8 -*-  
 3
 4from tinkerforge.ip_connection import IPConnection
 5from tinkerforge.bricklet_lcd_20x4 import LCD20x4
 6from tinkerforge.bricklet_temperature import Temperature
 7
 8# This class will use any LCD Bricklet and Temperature Bricklet that
 9# are connected to the PC and display the temperature on the LCD.
10#
11# The program should stay stable if Bricks are connected/disconnected,
12# if the Brick Daemon is restarted or if a Wi-Fi/RS485 connection is lost.
13# It will also keep working if you exchange the Master or one of the
14# Bricklets by a new one of the same type.
15#
16# If a Brick or Bricklet loses its state (e.g. callback configuration)
17# while the connection was lost, it will automatically be reconfigured
18# accordingly.
19class ExampleRugged:
20    HOST = "localhost"
21    PORT = 4223
22
23    def __init__(self):
24        self.lcd = None
25        self.temp = None
26
27        # Create IP Connection
28        self.ipcon = IPConnection() 
29
30        # Register IP Connection callbacks
31        self.ipcon.register_callback(IPConnection.CALLBACK_ENUMERATE, 
32                                     self.cb_enumerate)
33        self.ipcon.register_callback(IPConnection.CALLBACK_CONNECTED, 
34                                     self.cb_connected)
35
36        # Connect to brickd, will trigger cb_connected
37        self.ipcon.connect(ExampleRugged.HOST, ExampleRugged.PORT) 
38
39        self.ipcon.enumerate()
40
41    # Callback switches lcd backlight on/off based on lcd button 0
42    def cb_button_pressed(self, button):
43        if self.lcd:
44            if button == 0:
45                if self.lcd.is_backlight_on():
46                    self.lcd.backlight_off()
47                else:
48                    self.lcd.backlight_on()
49
50    # Callback updates temperature displayed on lcd
51    def cb_temperature(self, temperature):
52        if self.lcd:
53            self.lcd.clear_display()
54            s = 'Temperature: {0:.2f}{1:c}C'.format(temperature/100.0, 0xdf)
55            self.lcd.write_line(0, 0, s)
56
57    # Callback handles device connections and configures possibly lost 
58    # configuration of lcd and temperature callbacks, backlight etc.
59    def cb_enumerate(self, uid, connected_uid, position, hardware_version, 
60                     firmware_version, device_identifier, enumeration_type):
61        if enumeration_type == IPConnection.ENUMERATION_TYPE_CONNECTED or \
62           enumeration_type == IPConnection.ENUMERATION_TYPE_AVAILABLE:
63            
64            # Enumeration is for LCD Bricklet
65            if device_identifier == LCD20x4.DEVICE_IDENTIFIER:
66                # Create lcd device object
67                self.lcd = LCD20x4(uid, self.ipcon) 
68                self.lcd.register_callback(self.lcd.CALLBACK_BUTTON_PRESSED, 
69                                           self.cb_button_pressed)
70                self.lcd.clear_display()
71                self.lcd.backlight_on()
72            # Enumeration is for Temperature Bricklet
73            if device_identifier == Temperature.DEVICE_IDENTIFIER:
74                # Create temperature device object
75                self.temp = Temperature(uid, self.ipcon) 
76                self.temp.register_callback(self.temp.CALLBACK_TEMPERATURE, 
77                                            self.cb_temperature)
78
79                self.temp.set_temperature_callback_period(50)
80
81    # Callback handles reconnection of IP Connection
82    def cb_connected(self, connected_reason):
83        # Enumerate devices again. If we reconnected, the Bricks/Bricklets
84        # may have been offline and the configuration may be lost.
85        # In this case we don't care for the reason of the connection
86        self.ipcon.enumerate()
87        
88
89if __name__ == "__main__":
90    ExampleRugged()
91    raw_input('Press key to exit\n') # Use input() in Python 3