Archiv der Kategorie: JavaScript

Create your own workflow to visualize your TTN coverage

ttn-koln2.png

In short

To determine the radio coverage, GPS data is sent via TheThingsNetwork, processed with Node-Red and stored in an InfluxDB. The data is read from the database via JS and displayed graphically on a map.

The detailed version

This blog post will be the first of a series related to TheThingsNetwork. For some months now I have been actively involved in the development of the TheThingsNetwork in the city of Cologne. The TheThingsNetwork initiative aims to build an open and free wireless infrastructure for the Internet of Things. The community provides the gateways for use by everyone and the central infrastructure is provided by various data centers worldwide, for Europe by the Netherlands.

When building a radio infrastructure, the most important information is the range and coverage of the city in the area. The TTN Mapper from JP Meijers works very well for this application. If I had a smartphone that would be suitable for this app, this post would probably never have existed.
For my own purposes, however, I wanted to build a webpage that I could adapt flexibly to my own needs. In addition, it was a special attraction for me to familiarize myself with this topic and to master the task.

The Node

The first task was to build a TTN node equipped with a GPS module that sends the GPS data via the TTN. The construction of this node was similar to the node described by Bjoern in his blog. A GPS module is serially connected to an Arduino Pro Mini and an RFM95W is used to send the data. The circuits are powered by a lithium-ion battery and the voltage is stabilized by a low quiescent current LDO and a low dropout voltage type HX7333.  Even if the structure doesn’t look very professional, it still fulfils its function.

img_20171121_192556.jpg

The antenna used is an old GSM 900MHz window antenna. The only change to Bjoern’s software is that in my case OTAA activation is used.
The software checks the validity of the GPS data and sends latitude and longitude data encoded in 6 bytes. The relevant lines here:

void get_coords () {
  bool newData = false;
  unsigned long chars;
  unsigned short sentences, failed;
  float flat, flon;
  unsigned long age;

  // For one second we parse GPS data and report some key values
  for (unsigned long start = millis(); millis() - start < 1000;) {
    while (SoftS.available()) {
      char c = SoftS.read();
      Serial.write(c); // uncomment this line if you want to see the GPS data flowing
      if (gps.encode(c)) { // Did a new valid sentence come in?
        newData = true;
      }
    }
  }

  if ( newData ) {
    gps.f_get_position(&flat, &flon, &age);
    flat = (flat == TinyGPS::GPS_INVALID_F_ANGLE ) ? 0.0 : flat;
    flon = (flon == TinyGPS::GPS_INVALID_F_ANGLE ) ? 0.0 : flon;
  }

  gps.stats(&chars, &sentences, &failed);

  int32_t lat = flat * 10000;
  int32_t lon = flon * 10000;

  // Pad 2 int32_t to 6 8uint_t, big endian (24 bit each, having 11 meter precision)
  coords[0] = lat;
  coords[1] = lat >> 8;
  coords[2] = lat >> 16;

  coords[3] = lon;
  coords[4] = lon >> 8;
  coords[5] = lon >> 16;
  }
} ... 

The complete program code can be found in my git. Define an application and device in the TheThingsNetwork console and fill in the keys in the program code.
To decode the data in the TTN cloud define this function in the TTN Application Console.

function Decoder(b, port) {
 var lat = (b[0] | b[1]<<8 | b[2]<<16 | (b[2] & 0x80 ? 0xFF<<24 : 0)) / 10000;
 var lng = (b[3] | b[4]<<8 | b[5]<<16 | (b[5] & 0x80 ? 0xFF<<24 : 0)) / 10000;
return {
 location: {
 lat: lat,
 lng: lng
 },
 love: "TTN payload functions"
 };
}

Data Processing

Node-Red handles the further processing of the data from the TTN cloud. For the first attempts an installation on a RaspberryPi is sufficient or you can use an online version on https://fred.sensetecnic.com/

The gps-logger node is connected to the application in the TTN cloud and receives json fomatted data. The function node decodes the data and prepares the data for the influxdb. The influxdb node finally writes the data to the influxdb. For each gateway receiving the data a record is written in the database. Later when visualizing the data on the map only the record with the highest rssi will be drawn to the map. The record will keep data for the gps location of the node, the gps location and ID of the receiving gateway, rssi, snr, the node’s counter of the record and the device ID of the node. Also the distance between the node and the gateway is calculated and written to the database but not used so far. The structure of the record is defined in the multiple-readings function node.

var lgid = msg.metadata.gateways.length;
var array_aussen = [];
var array_innen = [];
var last_time;
for (i = 0; i < lgid; i++) {
 array_innen = [{
 counter: msg.counter,
 rssi: msg.metadata.gateways[i].rssi,
 snr: msg.metadata.gateways[i].snr,
 lat_gw: msg.metadata.gateways[i].latitude,
 lon_gw: msg.metadata.gateways[i].longitude,
 no_gw: lgid,
 lat_sense: msg.payload.location.lat,
 lon_sense: msg.payload.location.lng,
 dist2gw: distance(msg.metadata.gateways[i].latitude,msg.metadata.gateways[i].longitude,msg.payload.location.lat,msg.payload.location.lng),
 time: new Date(msg.metadata.gateways[i].time).getTime() * 1000000 || 0
 },
 {
 dev_id: msg.dev_id,
 gtw_id: msg.metadata.gateways[i].gtw_id
 }
 ];
 if (array_innen[0].time === last_time) {
 array_innen[0].time += 1000;
 }
 array_aussen.push(array_innen);
}
var msg1 = {};
msg1.payload = array_aussen;
var msg2 = {};
msg2.payload = array_innen[0].time;
return [msg1, msg2];
function distance(gw_lat, gw_lon,sense_lat, sense_lon){
 if(sense_lat<1 || sense_lon < 1){
 return -1;
 }
 else {
 return Math.round(Math.sqrt(Math.pow(70.12*(gw_lon-sense_lon),2) + Math.pow(111.3*(gw_lat-sense_lat),2))*1000);
 }}

The Website

The far more difficult part of the task was the creation of the website. My Javascript knowledge was rather rudimentary in the beginning and I had to learn a lot while programming the website. For those who want to deal with this, the source code is located on the git. The website performs the following functions: The data is fetched by ajax from the influxdb, first the data of the receiving gateways, then the gps data of the node. The data is displayed as colored squares with the JS extension LeafletJS on an Openstreetmap. If you move the mouse over the squares, detailed data such as rssi, snr, number of receiving gateways and ID of the gateway with the highest rssi are displayed. The coding of color of the squares for rssi is the same as in the ttnmapper. If you hover over a gateway, the gateway ID is displayed.

The time period can be limited by passing HTTP GET parameters. In this way, you can also select whether the map should be colored or black and white. To overpass the parameters a simple http form is provided. A separately recorded gpx track can be placed under the data via a control element on the page. In this way, it is possible to illustrate very clearly where there is no radio coverage. The following video shows the possibilities that the website offers perhaps best.

VIDEO – coming soon

last but not least

The workflow described here may not be suitable for processing a lot of mapping data. I provide the members of the TTN community in Cologne with access to this server, so the amount of data is limited. The workflow is very simple and you don’t need to have a very high programming knowledge to understand it. Maybe this will be also interesting for other communities. You are welcome to try out the website, here in direct access to all available timeseries data or via the filter page with input option for the time span and selection of the optional b/w representation.

Advertisements

Daten in der Cloud – Visualisierung auf dem Bildschirm

screenshot1Einleitung

In den letzten Wochen habe ich mich intensiv mit dem Thema IoT beschäftigt. Auf der Suche nach Diensten zur Speicherung von Daten in der Cloud bin ich auf data.sparkfun.com aufmerksam geworden. Dieser Dienst eignet sich gerade für Programmieranfänger hervorragend Daten strukturiert in der Cloud abzulegen.

In diesem Blogpost beschreibe ich eine einfache Methode auf data.sparkfun abgelegte numerische Daten grafisch zu präsentieren. Dabei bediene ich mich wieder des Javascript Moduls dygraphs, das ich schon in früheren Blogposts genutzt habe, um Daten grafisch darzustellen.

Der Dienst data.sparkfun

Die Konfiguration einer Datentabelle auf data.sparkfun ist denkbar einfach, so dass ich an dieser Stelle auf eine Anleitung verzichten möchte.

stream-create

Mit nur wenigen Klicks hat man eine Datentabelle (data stream) angelegt. Auf der Webseite sind nur wenige Eingaben zu machen. Der Dienst ist kostenlos und anonym, allerdings ist die Größe des Streams auf 50MB beschränkt, die ältesten Daten werden bei Überschreitung gelöscht. Die Daten sind öffentlich, jeder, der die url kennt, kann die Daten abrufen. Eine Sicherheit für die Verfügbarkeit der Daten wird nicht gegeben. Nichtsdestotrotz ist es ein hervorragender Dienst, um mit dem IoT erste Erfahrungen zu machen.

Die Daten und deren Darstellung

screenshot2Über die Webseite data.sparkfun.com kann man seine Daten tabellarisch ansehen und als Datei im csv oder json Format herunterladen. Eine grafische Darstellung ist hier nicht vorhanden. Anleitungen zur grafischen Darstellung mit Google Charts oder als eigene Platform (analog.io) existieren, sind mir aber entweder zu unflexibel oder zu google-lastig. Mein Favorit ist nach wie vor DyGraphs, zur Nutzung mit data.sparkfun gab es aber bisher keine Anleitung, so dass ich selbst kreativ werden musste.  Dabei habe ich wieder so einiges über JavaScript lernen müssen / dürfen und meine Erfahrungen gebe ich wie immer gerne weiter.

JavaScript eignet sich für diese Aufgabe im Gegensatz zu PHP besonders deshalb, weil kein separater Server zum Aufruf dieser Webseite benötigt wird. Die html-Datei mit der Formatierung der Webseite kann lokal auf dem eigenen Rechner liegen, die Verarbeitung findet komplett im Browser statt.

Die hier genutzte html-Beispieldatei greift auf einen aktiven Stream auf data.sparkfun zu und zeigt im Screenshot oben die Entladung und Ladung eines Li-Ionen Akkus, über den der Arduino mit Ethernetshield, der die Daten auf data.sparkfun pushed, gleichzeitig mit Strom  versorgt wird.

Die Struktur der html-Datei erkläre ich hier, damit sollte die Anpassung auf einen eigenen Stream recht einfach sein.

screenshot3Zuoberst findet man die üblichen HTML Tags im Kopfbereich einer html-Datei und die Angabe der Quelle für 2 JavaScript-Module, hier als hosted Version, die auskommentierten Zeilen nutzt man, wenn die Dateien lokal im gleichen Verzeichnis wie die html-Datei liegt. Es folgt eine einfache farbliche Formatierung der Webseite.

screenshot4Die nachfolgenden Zeilen sind in eine onload() Funktion eingebettet und definieren die Größe der späteren Grafik, die über die id=graphdiv2 später befüllt wird.

screenshot5Dies ist die Funktion zum Download der Daten von data.sparkfun. An dieser Stelle muss der public Key der eigenen Daten eingetragen werden. Über eine jquery Funktion werden die Daten von Sparkfun geladen. An dieser Stelle kann ein Filter definiert werden, entweder man lädt die Daten page-weise ( data: {page: 1};  ) oder nutzt einen der hier beschriebenen möglichen Filter zur Einschränkung der Zahl der Daten.  Der hier benutzte Filter „today“ für den timestamp ist nirgendwo dokumentiert und habe ich zufällig herausgefunden, also nicht wundern, wenn mit meinem Script eine leere Grafik erscheint. Für einen ersten Test kann man die Zeile auskommentieren.

screenshot6Die json-Daten müssen in ein Array überführt werden, dabei werte ich aus, wie groß der zeitliche Abstand der Daten ist und entscheide darüber, ob die Datenpunkte mit Linien verbunden werden (hier 250.000 Sekunden, also etwas über 4 Minuten) .  Hier müssen die Namen der Datenfelder eingesetzt werden , in meinem Fall ubatt und ucc.

screenshot7Damit die zeitliche Darstellung der Daten korrekt ist, wird das gesamte Array in der Reihenfolge umgekehrt. Das Array wird dann an Dygraph übergeben mit einigen Parametern zur Darstellung und den Labeln für die Daten.

Die vollständige html-Datei liegt auf meinem Git zusammen mit dem Arduino Programm zum pushen der Daten.

Ausblick

Ich habe inzwischen den phant Server auch auf einem RaspberryPi laufen, funktioniert hervorragend. Leider habe ich den mqtt-output noch nicht ans laufen gebracht. Dieser Service ist bei Sparkfun leider sehr unzuverlässig, so dass ich davon – zumindest bei der hosted Version – erst mal abraten würde.
Speziell für den Arduino Uno werde ich einen Stream erstellen, wo alle analogen Eingänge als Integer und die digitalen Eingänge als Boolean 1/0 gepushed werden können. Auf einer Webseite soll man dann wählen können, welche Daten grafisch aufbereitet werden sollen. Auch das zeitliche filtern der Daten will ich auf der Webseite eingebbar machen.