CaribeWave 2016 — A thorough look at the tech stack

I took part, along with Thomas Grange and Alexandre Vallette, in the 2016 edition of the Caribe Wave tsunami exercise that takes place in the French West Indies since 2011.

The aim of our team was to find actionable technologies and methods to help communicate in the event of a major earthquake or tsunami, and try to disrupt the processes in place that date back to the post-war era (namely, sounding sirens that no one listens to).

The general Lantex/CaribeWave exercise is organized by the UNESCO, and is far broader, with real evacuations simulations with the firemen, army and police districts involved in more than 15 countries including Venezuela, Anguilla, Virgin Islands, Dominica, Grenadines, Barbados, etc .. (More on the Lantex/CaribeWave exercise here) but our mission is precisely focused on the technology and how it can help in situations like these, especially in the French West Indies.

It's a citizen initiative since the French government can't really be bothered with natural disasters.. which is a pity. But anyway.

Our plan included :

  • creating off the grid communication networks that can span 40 km and run off a car battery
  • deploying cheap seismic sensors to have a better response time when an earthquake arrives
  • creating an ad-hoc infrastructure to automatically generate messaging and alerting data that get sent to every person in the vicinity of a seismic event
  • as a matter of fact, everything that technology enables and that can help prevent a major human disaster in the (not so distant) future

So, off we went, fully equipped with Raspberry Pis, accelerometers, ADCs, Wifi antennas and SDR, to code and disrupt things !

This year, we had our HQ in Marie-Galante, an island off the shore of Guadeloupe, in the south :

View Larger Map

In this post I'm going to detail the full chain of applications that we have developed over the course of the five days, and the different technologies used to this effect. All this is a prototype system, and aims to be a proof-of-concept for what could be a real-life prevention system. This is our humble effort to prove that it is not so complicated.

TL,DR.

Check out all the pieces here : https://github.com/caribewave
... And thanks to fellow contributors Gael and Jérome.

The chain

The final result we put in place is the following system :

  • a network of Ethernet and WiFi-enabled accelerometer devices are deployed in an area

  • these devices continuously monitor the differential acceleration in all three axes and report if the norm of all axes goes above a certain threshold

  • these devices are remote controlled : we can change the threshold, take control, update the firmware, etc ... from a distant point

  • the data produced is sent to a central messaging broker (MQTT, you had guessed!)

  • a listener logs all the data securely and archive everything on a remote server

  • an alerter script checks if several sensors send consistent seismic data, and trigger alerts :

    • through MQTT again to be consumed by any end-user device
    • through Amazon SNS so as to send messages to phones in different ways (SMS, GCM, APNS, ...)
  • finally, a test app displays the actual status of all the sensors (through the MQTT messages), as well as the alert messages and the GCM messages that can be processed even when the app is killed or crashed.

The stack

Hardware / Sensors

We had a variety of accelerometers at hand during the operation : ADXL337, LIS331 and a MMA too. Combined with Raspberry Pi B+, we figured we needed to make a program that could accept input from all these models.

We settled for SPI as the standard protocol and hopefully we had a bunch of MCP3002 with us to act as ADC for the accelerometers that were analog (MMA and ADXL) — all the datasheets are here.

So we soldered different boards (one for each accelerometer) and exposed SPI pins to communicate with the Pi.

To create a program that could use the data from these sensors, we chose C++ as our language of choice, given the fantastic WiringPi library and the fact that C++ has some easier-to-handle API. for such a simple program.

The code is a very simple main.cpp file that is compiled against the wiringPi lib :

g++ main.cpp -lwiringPi

It outputs the data when a simple L2 norm goes over a defined threshold.

Caribe Wave Sensor Pusher — pushes sensor data to stdout for next stage.
Usage :
  ./main [type] [sampling rate] [trigger] [time span] [debug]

Arguments :
  - type: type of accelerometer : ADXL, LIS or MMA (string).
  - sampling rate: in milliseconds, between 0 and 1000.
  - trigger: trigger value in millig (max 1sec).
  - trigger time span: span time during which we keep outputting data after a trigger (max 2min).
  - debug: 1 or 0.

The data is then taken care of with the Pheromon system developed by weareants; In a nutshell, a nodejs program retrieves the outputted data and sends it to a central broker, while providing us with reverse SSH, remote control via a centralized back office.


This would prove very handy when you don't have physical access to all the sensors but still need to tweak the parameters or check on the health of any of them.

All the code is available here : https://github.com/caribewave/sensor-pusher (for the tiny C program) and https://github.com/caribewave/pheromon_client for the Pheromon client.

Message broker

This would come to no surprise if I say that MQTT was the backbone for all the messages that transited to and from the sensors.

Pheromon uses it by default and it's a very sensitive choice to make when network conditions are not always fully guaranteed (that is definitely the case in remote areas).

So off we went with mosquitto of course. We agreed on a very simple, no-namespace, endpoing naming paradigm :

  • measurement/{sensorid}/sismic for sensor data bubbling up to the server
  • alert/general for alerts coming down to the apps, leaving some leeway for other type of alerts in case we geolocate the user or define "zones" later on

We settled for a QoS of 1.

SNS, GCM

Now that all the data are coming to our servers in a timely fashion, we need to make decisions and send messages that can be processed by apps, websites, etc.. and alert the population for real.

For the decision-making process, the general concept is quite simple : if all the sensors (or a certain amount) trigger at the same time (i.e., in the same time frame), then we issue an alert with both MQTT and SNS.

It's the Python script that takes care of that :
https://github.com/caribewave/alerter/blob/master/caribewave/alerting.py
Most of the business logic is summed up in the prevent() method of the Alert class.

Then, we have a website dashboard of course, but we though about using a centralized messaging service to be able to reach as many people as possible.

We decided to try to use Google Cloud Messaging (and potentially Apple Messaging Service) through SNS, the Amazon push service for mobile that can handle various sub protocols quite easily.

With the simple installation of an Android App (covered later on), we could have access to notifications on the user device even when the app was not launched, or crashed, which is very interesting for this type of alerts (tsunamis, earthquake), for which you will definitely not use the app constantly to see if there is an event. It's a kind of "install and forget" use case, and GCM / APNS works perfectly well for this.

SNS adds a layer of abstraction above this and allows for a very simple system to send message to registered devices (a device is registered the moment it is launched at least once on the target device). We only need a token that is created by the app :

def create_endpoint(token):
    """
    Create an endpoint on SNS based on token
    and subscribe to alert topic
    """
    conn = connect()
    app_endpoint = conn.create_platform_endpoint(
        platform_application_arn=settings.SNS_APP_ID,
        token=token)
    endpoint_arn = (app_endpoint['CreatePlatformEndpointResponse']['CreatePlatformEndpointResult']['EndpointArn'])
    conn.subscribe(
        settings.SNS_ALERT_TOPIC,
        'application',
        endpoint_arn)


def send_message(message):
    conn = connect()
    conn.publish(message=message,
                 target_arn=settings.SNS_ALERT_TOPIC)

This token is sent via a simple get query to our server when the app launches for the first time; it's very easy to create in the Android app :

InstanceID instanceID = InstanceID.getInstance(this);
            String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
                    GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);

The service that takes care of notifications in the background is declared in the Manifest, like that :

<!-- [START gcm_receiver] -->
        <receiver
            android:name="com.google.android.gms.gcm.GcmReceiver"
            android:exported="true"
            android:permission="com.google.android.c2dm.permission.SEND" >
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                <category android:name="gcm.play.android.samples.com.gcmquickstart" />
            </intent-filter>
        </receiver>
        <!-- [END gcm_receiver] -->

        <!-- [START gcm_listener] -->
        <service
            android:name="wave.caribe.dashboard.services.CWGcmListenerService"
            android:exported="false" >
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            </intent-filter>
        </service>
        <!-- [END gcm_listener] -->
        <!-- [START instanceId_listener] -->
        <service
            android:name="wave.caribe.dashboard.services.CWInstanceIDListenerService"
            android:exported="false">
            <intent-filter>
                <action android:name="com.google.android.gms.iid.InstanceID"/>
            </intent-filter>
        </service>
        <!-- [END instanceId_listener] -->
        <service
            android:name="wave.caribe.dashboard.services.RegistrationIntentService"
            android:exported="false">
        </service>
The Android app

Thus, the app serves two purposes :

  • be a vehicle for cloud messaging notifications
  • display relevant information if an event happens

We factored a Mapbox map into the app with the geolocation of every sensor, and their status, so everybody can see when an event occurs somewhere in the area.

Moreover, the app displays the alert messages coming from MQTT (General alerts for instances) — here we can see a message in the top bar (in orange).

We added the elevation data to the Mapbox map as well, to pinpoint the relatively safe areas (the areas that are up a moutain or a hill) depicted in green here :

The whole chain responds in under 2 seconds when a sensor is triggered, which is pretty efficient considering all the layers involved and the potential delays introduced. All in all, it's very quick !

Final words

If you have your phone at hand, and it's connected to some kind of data connection, you will get a notification in the second, and that is pretty much the quickest way to alert someone nowadays. This gives you all the relevant info to know what short-term action you need to take to run away from a tsunami, get in a safe place, or help other people.

٭٭٭

We had a lot of fun designing this infrastructure for CaribeWave 2016. It's obviously far from perfect but it showcases what a few individuals can do in a few days to help alert population at a potentially large scale when a specific type of events, or a coordinated type of events, occur in a vicinity.

If you're interested and want to participate, please hit us up and we'll be happy to give you more details and explain how you can get involved in this simulation.

And of course the Github of the whole project is waiting for you to improve it !