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)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
using Tinkerforge;

// This class will use any LCD Bricklet and Temperature Bricklet that
// are connected to the PC and display the temperature on the LCD.
//
// The program should stay stable if Bricks are connected/disconnected,
// if the Brick Daemon is restarted or if a Wi-Fi/RS485 connection is lost.
// It will also keep working if you exchange the Master or one of the
// Bricklets by a new one of the same type.
//
// If a Brick or Bricklet loses its state (e.g. callback configuration)
// while the connection was lost, it will automatically be reconfigured
// accordingly.
class ExampleRugged
{
    private static string HOST = "localhost";
    private static int PORT = 4223;

    private static IPConnection ipcon = null;
    private static BrickletLCD20x4 lcd = null;
    private static BrickletTemperature temp = null;

    static void Main() 
    {
        // Create IP Connection
        ipcon = new IPConnection();

        // Register IP Connection callbacks
        ipcon.EnumerateCallback += EnumerateCB;
        ipcon.Connected += ConnectedCB;

        // Connect to brickd, will trigger cb_connected
        ipcon.Connect(HOST, PORT); 
        ipcon.Enumerate();

        System.Console.WriteLine("Press enter to exit");
        System.Console.ReadLine();
        ipcon.Disconnect();
    }

    // Callback updates temperature displayed on lcd
    static void TemperatureCB(BrickletTemperature sender, short temperature)
    {
        if(lcd != null)
        {
            lcd.ClearDisplay();
            string s = "Temperature: " + temperature/100.0 + (char)0xdf + "C";
            lcd.WriteLine(0, 0, s);
        }
    }

    // Callback switches lcd backlight on/off based on lcd button 0
    static void ButtonPressedCB(BrickletLCD20x4 sender, byte button)
    {
        if(lcd != null)
        {
            if(button == 0)
            {
                if(lcd.IsBacklightOn())
                {
                    lcd.BacklightOff();
                }
                else
                {
                    lcd.BacklightOn();
                }
            }
        }
    }

    // Callback handles device connections and configures possibly lost
    // configuration of lcd and temperature callbacks, backlight etc.
    static void EnumerateCB(IPConnection sender, string UID, string connectedUID, 
                            char position, short[] hardwareVersion, 
                            short[] firmwareVersion, int deviceIdentifier, 
                            short enumerationType)
    {
        if(enumerationType == IPConnection.ENUMERATION_TYPE_CONNECTED ||
           enumerationType == IPConnection.ENUMERATION_TYPE_AVAILABLE)
        {
            // Enumeration is for LCD Bricklet
            if(deviceIdentifier == BrickletLCD20x4.DEVICE_IDENTIFIER)
            {
                // Create lcd device object
                lcd = new BrickletLCD20x4(UID, ipcon);
                lcd.ButtonPressed += ButtonPressedCB;

                lcd.ClearDisplay();
                lcd.BacklightOn();
            }
            // Enumeration is for Temperature Bricklet
            if(deviceIdentifier == BrickletTemperature.DEVICE_IDENTIFIER)
            {
                // Create temperature device object
                temp = new BrickletTemperature(UID, ipcon);
                temp.Temperature += TemperatureCB;

                temp.SetTemperatureCallbackPeriod(50);
            }
        }
    }

    // Callback handles reconnection of IP Connection
    static void ConnectedCB(IPConnection sender, short connectReason)
    {
        // Enumerate devices again. If we reconnected, the Bricks/Bricklets
        // may have been offline and the configuration may be lost.
        // In this case we don't care for the reason of the connection
        ipcon.Enumerate();
    }
}

Python

Download (example_rugged.py)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#!/usr/bin/env python
# -*- coding: utf-8 -*-  

from tinkerforge.ip_connection import IPConnection
from tinkerforge.bricklet_lcd_20x4 import LCD20x4
from tinkerforge.bricklet_temperature import Temperature

# This class will use any LCD Bricklet and Temperature Bricklet that
# are connected to the PC and display the temperature on the LCD.
#
# The program should stay stable if Bricks are connected/disconnected,
# if the Brick Daemon is restarted or if a Wi-Fi/RS485 connection is lost.
# It will also keep working if you exchange the Master or one of the
# Bricklets by a new one of the same type.
#
# If a Brick or Bricklet loses its state (e.g. callback configuration)
# while the connection was lost, it will automatically be reconfigured
# accordingly.
class ExampleRugged:
    HOST = "localhost"
    PORT = 4223

    def __init__(self):
        self.lcd = None
        self.temp = None

        # Create IP Connection
        self.ipcon = IPConnection() 

        # Register IP Connection callbacks
        self.ipcon.register_callback(IPConnection.CALLBACK_ENUMERATE, 
                                     self.cb_enumerate)
        self.ipcon.register_callback(IPConnection.CALLBACK_CONNECTED, 
                                     self.cb_connected)

        # Connect to brickd, will trigger cb_connected
        self.ipcon.connect(ExampleRugged.HOST, ExampleRugged.PORT) 

        self.ipcon.enumerate()

    # Callback switches lcd backlight on/off based on lcd button 0
    def cb_button_pressed(self, button):
        if self.lcd:
            if button == 0:
                if self.lcd.is_backlight_on():
                    self.lcd.backlight_off()
                else:
                    self.lcd.backlight_on()

    # Callback updates temperature displayed on lcd
    def cb_temperature(self, temperature):
        if self.lcd:
            self.lcd.clear_display()
            s = 'Temperature: {0:.2f}{1:c}C'.format(temperature/100.0, 0xdf)
            self.lcd.write_line(0, 0, s)

    # Callback handles device connections and configures possibly lost 
    # configuration of lcd and temperature callbacks, backlight etc.
    def cb_enumerate(self, uid, connected_uid, position, hardware_version, 
                     firmware_version, device_identifier, enumeration_type):
        if enumeration_type == IPConnection.ENUMERATION_TYPE_CONNECTED or \
           enumeration_type == IPConnection.ENUMERATION_TYPE_AVAILABLE:
            
            # Enumeration is for LCD Bricklet
            if device_identifier == LCD20x4.DEVICE_IDENTIFIER:
                # Create lcd device object
                self.lcd = LCD20x4(uid, self.ipcon) 
                self.lcd.register_callback(self.lcd.CALLBACK_BUTTON_PRESSED, 
                                           self.cb_button_pressed)
                self.lcd.clear_display()
                self.lcd.backlight_on()
            # Enumeration is for Temperature Bricklet
            if device_identifier == Temperature.DEVICE_IDENTIFIER:
                # Create temperature device object
                self.temp = Temperature(uid, self.ipcon) 
                self.temp.register_callback(self.temp.CALLBACK_TEMPERATURE, 
                                            self.cb_temperature)

                self.temp.set_temperature_callback_period(50)

    # Callback handles reconnection of IP Connection
    def cb_connected(self, connected_reason):
        # Enumerate devices again. If we reconnected, the Bricks/Bricklets
        # may have been offline and the configuration may be lost.
        # In this case we don't care for the reason of the connection
        self.ipcon.enumerate()
        

if __name__ == "__main__":
    ExampleRugged()
    raw_input('Press key to exit\n') # Use input() in Python 3