Server RMAP¶
Analisi funzionalità RMAP¶
Introduzione¶
Le funzionalità offerte dal server RMAP (https://rmap.cc) sono implementate usando i seguenti software e servizi (sono elencati solo quelli significativi):
Broker AMQP (RabbitMQ) per la distribuzione di dati in tempo reale attraverso un sistema di code, sia da stazione a server che da server a server.
Broker MQTT (Mosquitto) per l’invio di dati da stazioni al server.
Arkimet per l’archiviazione dei dati storici
DB-All.e per l’archiviazione dei dati recenti
Una singola applicazione web (Django web framework) che gestisce
Sistema di autenticazione
Visualizzazione dei dati
Registrazione utenti
Configurazione di metadati e firmware delle stazioni
Inserimento manuale dati e immagini georeferenziati
Visualizzazione personalizzata per RainBO
Data ingestion¶
Il data ingestion riguarda principalmente l’accoglimento di dati da stazioni via MQTT e AMQP. I dati che arrivano via MQTT sono poi inoltrati al broker AMQP, che è il nucleo della movimentazione dei dati all’interno del sistema. I client che devono inviare dati via MQTT o AMQP devono passare da un sistema di autenticazione e autorizzazione, sostanzialmente per garantire che i dati siano inviati solo da utenti autenticati e che non vadano a sovrapporsi a dati altrui. Entrambi i broker interrogano il sistema di autenticazione, un servizio web che implementa gli endpoint richiesti da RabbitMQ e Mosquitto. Il servizio di autorizzazione su AMQP (cioè cosa può pubblicare un utente autenticato) è invece delegato al demone identvalidationd, che prende i dati dalla coda di ingresso dell’utente e passa alla coda di ingestion solo i dati per cui il campo ident è uguale al nome utente. I dati che passano quest’ultimo controllo sono poi inviati:
Ad altre code AMQP, ad esempio per forniture esterne o per altri processamenti. Su due di queste code sono inoltrati i dati per il SIMC (archiviati in Arkimet in formato VM2), una per le stazioni delle reti claster e rmap e l’altra per la rete profe.
Al database DB-All.e che contiene i dati recenti.
Ci sono inoltre alcuni moduli per l’accoglimento di dati da sorgenti che non usano AMQP o non usano il formato BUFR (e.g. Luftdaten).
Configurazione delle stazioni¶
Questa funzionalità permette l’aggiornamento della configurazione e del firmware delle stazioni STIMA. L’aggiornamento può essere fatto via HTTP o AMQP, previa autenticazione presso il corrispondente servizio di autenticazione.
Registrazione utenti¶
Questa funzionalità permette di registrare gli utenti attraverso un classico processo di iscrizione: l’utente compila una form e riceve una email per la conferma dell’avvenuta registrazione. Ovviamente, c’è un dialogo con il servizio di autenticazione.
Visualizzazione dei dati¶
Questo servizio permette di visualizzare i dati archiviati (DB-All.e e Arkimet) sia su mappa che su grafico. Non c’è servizio di autenticazione e autorizzazione perchè si presuppone che tutti i dati siano pubblici. Questo sistema è probabilmente necessario per i dati della rete amatoriale e quindi è necessario che il servizio corrispondente di data ingestion sia collegato all’importatore dei dati su DB-All.e e Arkimet.
Cosudo¶
Cosudo permette di analizzare i dati osservati per identificare anomalie, confrontando i dati da stazione con dati radar, satellite e previsti. Inoltre, permette all’operatore di invalidare dei dati: tali invalidazioni sono poi inviate ai sistemi del SIMC per applicarle sull’archivio.
È una applicazione che non necessita di accesso dall’esterno e deve avere a disposizione i dati dall’archivio del SIMC.
Il sistema di autenticazione è necessario poiché, essendo ospitato sul server rmap.cc, deve essere reso privato.
Non è ancora operativo e mancano i flussi di alimentazione dei dati.
Inserimento manuale dei dati¶
Questa funzionalità permette l’inserimento manuale, da parte di operatori, di dati e immagini via HTTP e AMQP. I dati attualmente sono le osservazioni della neve e del tempo (quest’ultimo all’interno del progetto RainBO). Si appoggia al sistema di autenticazione.
RainBO¶
È l’interfaccia per un progetto, che permette la visualizzazione con delle viste personalizzate per i seguenti servizi:
Visualizzazione dei dati
Inserimento manuale dei dati
Registrazione utenti
Interfaccia web¶
L’accesso da browser al sistema per alcune funzionalità, quali
Registrazione utente
Configurazione manuale delle stazioni
Visualizzazione dati
Inserimento manuale di dati
Sono offerte da un sistema monolitico, in cui tutti i vari pezzi sono interconnessi. È possibile separarli, ma è richiesto un intervento non banale sul frontend che può essere eseguito solo a valle dell’organizzazione dei vari pezzi di RMAP su diversi host.
Se una funzionalità usa varie app Django e deve quindi “assemblare” varie interfacce insieme, allora è necessario fare un repository per la singola funzionalità che dipende dalle app Django richieste.
Porte utilizzate¶
porta |
protocollo |
server |
servizio |
RMAP server |
RMAP data ingestion |
RMAP backend |
---|---|---|---|---|---|---|
80 |
HTTP |
apache |
download conf e firmware (Stima V3) |
X |
X |
|
442 |
HTTPS TLS con pre shared Key |
stunnel |
download conf e firmware (Stima v4) |
X |
X |
|
443 |
HTTPS (SSL/TLS) |
apache |
gestione backend e visualizzazione dati |
X |
X |
|
5925 |
HTTP |
monit |
monitoraggio daemoni RMAP |
X |
X |
|
1883 |
MQTT |
mosquitto |
pubblicazioni dati stazione (Stima V3) |
X |
X |
|
5671 |
AMQPS (SSL/TLS) |
rabbit-mq |
pubblicazione e distribuzione dati |
X |
X |
|
5672 |
AMQP |
rabbit-mq |
pubblicazione e distribuzione dati |
X |
X |
|
8883 |
MQTTS TLS con pre shared Key |
mosquitto |
pubblicazione stazioni (Stima V4) |
X |
X |
|
8884 |
MQTTS (SSL/TLS) WEBSOCKET |
mosquitto |
monitoraggio MQTT da web |
X |
X |
|
15672 |
HTTP |
rabbit-mq |
Management Plugin |
X |
X |
X |
Documentazione implementazione¶
Il funzionamento del back-end e del front-end è basato su due broker, una suite di applicazioni Django, alcuni tools e da una suite di daemon.
I dati seguono flussi e archivi differenti secondo questa classificazione:
stazione fissa |
Stazione mobile |
|
livello dati sample |
sample_fixed |
sample_mobile |
livello dei dati report |
report_fixed |
report_mobile |
Le quattro categorie corrispondono quindi a differenti root path MQTT, differenti exchange e queue AMQP, differenti daemon. Corrispondono anche a quattro differenti DataBase di DB.all.e per i dati recenti e a quattro macro dataset Arkimet poi eventualmente sottosezionati. Ecco un esempio di struttura dataset di Arkimet:
├── report_fixed
│ ├── agrmet
│ ├── boa
│ ├── claster
│ ├── dpcn-basilicata
│ ├── dpcn-bolzanoboze
│ ├── dpcn-calabria
│ ├── dpcn-campania
│ ├── dpcn-lazio
│ ├── dpcn-liguria
│ ├── dpcn-lombardia
│ ├── dpcn-marche
│ ├── dpcn-molise
│ ├── dpcn-piemonte
│ ├── dpcn-puglia
│ ├── dpcn-sardegna
│ ├── dpcn-sicilia
│ ├── dpcn-umbria
│ ├── dpcn-veneto
│ ├── fixed
│ ├── locali
│ ├── mnw
│ ├── report_fixed_duplicates
│ ├── report_fixed_error
│ ├── simnbo
│ ├── simnpr
│ ├── spdsra
│ └── urbane
├── report_mobile
│ ├── report_mobile
│ ├── report_mobile_duplicates
│ └── report_mobile_error
├── sample_fixed
│ ├── sample_fixed
│ │ └── sample_fixed
│ ├── sample_fixed_duplicates
│ └── sample_fixed_error
└── sample_mobile
├── sample_mobile
├── sample_mobile_duplicates
└── sample_mobile_error
Configurazione stazioni¶
Le configurazioni risiedono sul server. Possono essere scaricate e uplodate sul server. Le configurazioni devono essere trasferite alle stazioni e devono sempre essere allineate. Le stazioni Stima si possono configurare con i seguenti formati e trasporti:
trasporto Seriale |
trasporto HTTP |
tasporto http PSK |
SD card |
download/upload server |
|
JSON-RPC |
# |
||||
notification JSON-RPC |
# |
# |
|||
dump DB in json |
# |
# |
|||
file binario |
# |
queste configurazioni sono utilizzate differentemente a seconda del modello di stazione:
JSON-RPC |
notification JSON-RPC |
dump DB in json |
file binario |
|
StimaWifi |
# |
|||
Stima V3 |
# |
# |
||
Stima V4 |
# |
# |
Specifiche per immagini georeferenziate¶
Le immagini devono essere in formato jpeg e usare exif per i metadati.
Vengono utilizzati i seguenti metadati:
Latitude/Longitude (GPSIFD.GPSLatitude/GPSIFD.GPSLongitude)
reftime (ImageIFD.DateTime)
imagedescription (ImageIFD.ImageDescription)
usercomment (ExifIFD.UserComment)
Specifiche per file di configurazione stazione¶
Il file è un dump in json del DB usato da Django relativo solo alle tabelle di interesse per la configurazione. Questo un esempio:
[
{
"model": "stations.stationmetadata",
"fields": {
"name": "stimawifi",
"active": true,
"slug": "stimawifi",
"user": [
"paperino"
],
"ident": "",
"lat": 44.48858,
"lon": 11.37099,
"network": "fixed",
"mqttrootpath": "sample",
"mqttmaintpath": "maint",
"category": "good",
"type": "stimav2"
}
},
{
"model": "stations.board",
"fields": {
"name": "default",
"active": true,
"slug": "default",
"category": "template",
"type": 0,
"sn": null,
"stationmetadata": [
"stimawifi",
[
"paperino"
]
]
}
},
{
"model": "stations.sensor",
"fields": {
"active": true,
"name": "Dust",
"driver": "I2C",
"type": [
"SPS"
],
"i2cbus": null,
"address": 105,
"node": null,
"timerange": "254,0,0",
"level": "103,2000,-,-",
"board": [
"default",
[
"stimawifi",
[
"paperino"
]
]
]
}
},
{
"model": "stations.sensor",
"fields": {
"active": true,
"name": "Temperature_Humidity",
"driver": "I2C",
"type": [
"SHT"
],
"i2cbus": null,
"address": 68,
"node": null,
"timerange": "254,0,0",
"level": "103,2000,-,-",
"board": [
"default",
[
"stimawifi",
[
"paperino"
]
]
]
}
},
{
"model": "stations.sensor",
"fields": {
"active": true,
"name": "CO2",
"driver": "I2C",
"type": [
"SCD"
],
"i2cbus": null,
"address": 97,
"node": null,
"timerange": "254,0,0",
"level": "103,2000,-,-",
"board": [
"default",
[
"stimawifi",
[
"paperino"
]
]
]
}
},
{
"model": "stations.transportmqtt",
"fields": {
"active": true,
"mqttsampletime": 30,
"mqttserver": "test.rmap.it",
"mqttuser": "paperino",
"mqttpassword": "wFCeWf4ZqY",
"mqttpskkey": "648A67186FBF033E8A508282EEA74767",
"board": [
"default",
[
"stimawifi",
[
"paperino"
]
]
]
}
},
{
"model": "stations.transporttcpip",
"fields": {
"active": true,
"name": "stima",
"ntpserver": "it.pool.ntp.org",
"gsmapn": "ibox.tim.it",
"pppnumber": "*99#",
"board": [
"default",
[
"stimawifi",
[
"paperino"
]
]
]
}
},
{
"model": "stations.stationconstantdata",
"fields": {
"active": true,
"btable": "B01019",
"value": "stimawifi",
"stationmetadata": [
"stimawifi",
[
"paperino"
]
]
}
},
{
"model": "stations.stationconstantdata",
"fields": {
"active": true,
"btable": "B07030",
"value": "400",
"stationmetadata": [
"stimawifi",
[
"paperino"
]
]
}
}
]
Esempio di notification JSON-RPC¶
{"jsonrpc": "2.0", "method": "configure", "params": {"reset": true}}
{"jsonrpc":"2.0","result":{},"id":0}
{"jsonrpc": "2.0", "method": "configure", "params": {"sd": {"B01019": "stimawifi"}}}
{"jsonrpc":"2.0","result":{},"id":0}
{"jsonrpc": "2.0", "method": "configure", "params": {"sd": {"B07030": "400"}}}
{"jsonrpc":"2.0","result":{},"id":0}
{"jsonrpc": "2.0", "method": "configure", "params": {"mqttrootpath": "1/sample/paperino//1137099,4448858/fixed/"}}
{"jsonrpc":"2.0","result":{},"id":0}
{"jsonrpc": "2.0", "method": "configure", "params": {"mqttmaintpath": "1/maint/paperino//1137099,4448858/fixed/"}}
{"jsonrpc":"2.0","result":{},"id":0}
{"jsonrpc": "2.0", "method": "configure", "params": {"mqttrpcpath": "1/rpc/paperino//1137099,4448858/fixed/"}}
{"jsonrpc":"2.0","result":{},"id":0}
{"jsonrpc": "2.0", "method": "configure", "params": {"mqttsampletime": 30, "mqttserver": "test.rmap.it"}}
{"jsonrpc":"2.0","result":{},"id":0}
{"jsonrpc": "2.0", "method": "configure", "params": {"mqttuser": "paperino", "mqttpassword": "77CeWf4ZqY"}}
{"jsonrpc":"2.0","result":{},"id":0}
{"jsonrpc": "2.0", "method": "configure", "params": {"mqttpskkey": "0x328467156FBF033E8A508282EEA74767"}}
{"jsonrpc":"2.0","result":{},"id":0}
{"jsonrpc": "2.0", "method": "configure", "params": {"stationslug": "stimawifi", "boardslug": "default"}}
{"jsonrpc":"2.0","result":{},"id":0}
{"jsonrpc": "2.0", "method": "configure", "params": {"ntpserver": "it.pool.ntp.org"}}
{"jsonrpc":"2.0","result":{},"id":0}
{"jsonrpc": "2.0", "method": "configure", "params": {"gsmapn": "ibox.tim.it"}}
{"jsonrpc":"2.0","result":{},"id":0}
{"jsonrpc": "2.0", "method": "configure", "params": {"driver": "I2C", "type": "SPS", "node": null, "address": 105, "mqttpath": "254,0,0/103,2000,-,-/"}}
{"jsonrpc":"2.0","result":{},"id":0}
{"jsonrpc": "2.0", "method": "configure", "params": {"driver": "I2C", "type": "SHT", "node": null, "address": 68, "mqttpath": "254,0,0/103,2000,-,-/"}}
{"jsonrpc":"2.0","result":{},"id":0}
{"jsonrpc": "2.0", "method": "configure", "params": {"driver": "I2C", "type": "SCD", "node": null, "address": 97, "mqttpath": "254,0,0/103,2000,-,-/"}}
{"jsonrpc":"2.0","result":{},"id":0}
{"jsonrpc": "2.0", "method": "configure", "params": {"save": true}}
{"jsonrpc":"2.0","result":{},"id":0}
{"jsonrpc": "2.0", "method": "reboot"}
{"jsonrpc":"2.0","result":{},"id":0}
Broker MQTT¶
Le stazioni Stima comunicano i dati al broker differentemente a seconda della versione:
stazioni StimaWiFi: comunicano in WiFi in chiaro, tramite protocollo MQTT
stazioni Stima V3: comunicano in GSM in chiaro, tramite protocollo MQTT
stazioni Stima V4: comunicano in TLS con PSK (Pre-Shared Key), tramite protocollo MQTTS (PSK)
Il broker MQTT (mosquitto) authentica e autorizza tramite un apposito plugin. Utilizza l'hash delle password utente, le chiavi PSK, le ACL; queste vengono ottenute da file o da un server di autenticazione tramite API http. La generazione del file se necessario piò essere fatta con il tool rmapctrl.
Mosquitto comunica tramite un terzo protocollo, MQTT con SSL/TLS su Websocket utilizzato per funzionalità di monitoraggio delle stazioni meteo; tramite javascript nel web browser. Gli operatori che gestiscono le varie stazioni meteo possono attivare il monitoraggio su websocket per verificare i messaggi pubblicati dalla stazione sul broker evitando la necessità di avere un apposito client MQTT.
Ogni stazione può pubblicare solamente sul topic mqtt per cui è stata configurata e quindi autorizzata, in base a utente, rete, latitudine e longitudine. Ogni autenticazione e autorizzazione corrisponde a una richiesta http, ma con apposita cache del plugin di mosquitto.
Il plugin di mosquitto è una versione appositamente modificata: https://github.com/r-map/mosquitto-auth-plug
Se configurato a tale scopo il broker alle richieste di autenticazione/autorizzazione, nel caso in cui non sia disponibile il servizio http ricade su un file statico. Quando la configurazione hardware lo indichi come opportuno (separazione fisica della data ingestion) il file statico, utilizzato come sistema di autenticazione di backup, deve essere sincronizzato tramite procedura schedulata dal server di backend verso il server di data ingestion in modo da consentire comunque l’autenticazione delle stazioni anche in caso di failure del backend (il sistema non consentirà per esempio l’aggiunta o lo spostamento di stazioni ma non si bloccherà la pubblicazione dei dati).
I dati, una volta autenticate le stazioni sul backend e pubblicati tramite il broker MQTT sono disponibili ai subscriber, principalmente ai daemoni per la conversione di formato e l'invio come messaggi AMQP.
Tools¶
Generazione dei file di autenticazione/autorizzazione
Per mantenere allineato il processo di autenticazione sul broker MQTT e consentire l’autenticazione delle stazioni, anche in caso di failure del server di backend, è utilizzabile il tool rmapctrl che deve generere i seguenti file:
file.pwd
aclfile
file.psk
Una volta copiati i file in /etc/mosquitto/ sul server di data ingestion, è necessario effettuare un reload del servizio mosquitto.service in modo che i file aggiornati vengano recepiti correttamente; questo normalmente viene fatto solo in caso di modifica degli stessi file.
Daemon¶
report2observationd
Il demone (report2observationd) effettua una trasformazione dei messaggi che arrivano inizialmente compressi (vedi estensioni protocollo RMAP over MQTT), li decomprime e li pubblica nuovamente, per cui arrivano sul broker MQTT in forma decompressa.
URL¶
Se le URLs configurate tornano HTTP status code == 2xx, allora la authentication / authorization ha successo. Se lo status code == 4xx, authentication / authorization fallisce. Per uno status code == 5xx o server Unreachable, la richiesta HTTP sarà ritentata fino al raggiungimento di http_retry_count. Se tutti i tentativi falliscono e nessun altro backend ha successo, allora torna un errore e il client è disconnesso.
Configurazioni Mosquitto per il back-end http:
differenti modi di autenticare l'utente:
auth_opt_http_getuser_uri /auth/auth
auth_opt_http_getuser_uri /auth/auth_sha
auth_opt_http_getuser_uri /auth/sha
auth_opt_http_getuser_uri /auth/pskkey
verifica autorizzazioni:
auth_opt_http_superuser_uri /auth/superuser
auth_opt_http_aclcheck_uri /auth/acl
Broker AMQP¶
Il brocker AMQP (rabbitmq) svolge queste funzioni principali:
fornisce AMQP come protocollo per lo scambio dati
gestisce lo scambio interno dei messaggi sostanzialmente come sistema di buffering persistente
gestisce accoglienza e autorizzazione relativamente a: - dati in formato json (secondo specifiche RMAP) - immagini georeferenziate - configurazioni stazioni mettendo poi a disposizione questi dati ad appositi archiviatori
mette a disposizione un sistema per lo scambio dati tra fornitori e consumatori di dati (grosse moli di dati)
Viene utilizzato un solo tipo di exchange: fanout
I producer inviano dati agli Exchange e i consumer li prelevano dalle Queue. La gestione e il monitoraggio del broker avviene tramite l’accesso all’interfaccia web di RabbitMQ. All’accesso viene visualizzata la dashboard con statistiche varie, messaggi accodati, accodati, connessioni, ecc…
Il numero di messaggi in stato Ready può essere un buon indicatore in caso di problemi, se il numero cresce in maniera importante e i messaggi non vengono scodati.
Nella sezione Exchanges è possibile gestire quelli esistenti oppure configurarne di nuovi.
Cliccando sul nome del Exchange si viene rimandati al dettaglio della sua configurazione e alla definizione dei Bindings, ovvero dove vengono indirizzati i messaggi pubblicati: la Queue di destinazione
Exchanges → Queue
ad esempio: rmap.mqtt.bufr.report_fixed → arpaer.out.bufr.report_fixed&validated
Nella sezione Queues & Streams vengono gestite e definite le code di destinazione dei messaggi collezionati dal Exchange.
Qui posso controllare il numero di messaggi disponibili nella coda, non ancora confermati, ecc… Solitamente se tutto funziona correttamente la coda dovrebbe risultare sempre vuota, in quanto il consumer ha recuperato correttamente tutti i messaggi pubblicati.
In questa sezione è possibile spostare i messaggi da una coda ad un’altra (Move messages), cancellare definitivamente la coda e tutti i suoi messaggi (Delete Queue) oppure cancellare tutti i messaggi all'interno della coda (Purge Messages).
Nella sezione Admins vengono definiti gli utenti necessari solo al broker AMQP e non utilizzati dal resto del sistema di authenticazione. Questi saranno quindi solo fornitori e consumatori di dati esterni. Qui vengono definite le autorizzazioni dell'utente secondo una precisa definizione di regexp. A esempio per l’utente paperino sono le seguenti:
virtual host utilizzato è il default, ovvero “ / ”
non ha permessi di configurazione (campo vuoto in fase di definizione)
ha permessi di lettura e scrittura in tutto ciò (exchange e queue) che inizia con il suo nome utente (^paperino..*), in cui potrà leggere e pubblicare dati
Definizione nuovo fornitore o consumatore di dati¶
La definizione di un nuovo fornitore di dati o consumatore di dati è ottenuta da:
creazione utente con privilegi write e read con regular expression ^utente..*
creazione queue con eventuale Message TTL (se vuoto è indefinito, altrimenti imposta il valore massimo in millisecondi di permanenza dei messaggi nella queue, una volta superato quel valore i messaggi vengono rimossi)
creazione exchange con binding alla queue creata al punto precedente
Nomenclatura convenzionale¶
La sintassi utilizzata nella definizione di exchange e code è autoesplicativa e basata sul punto come separatore tra campi
Fornitore: - exchange → utente.in.formato.descrizione
Consumatore: - queue → utente.out.formato.descrizione
utente = nome utente definito in fase di creazione in/out = direzione operazione (in per fornitore, out per consumatore) formato = tipologia di output (es. json, xml, bufr) descrizione = label descrittiva dei dati in transito
Ogni utente ha accesso in lettura e scrittura a exchange e code che iniziano con il Name del proprio utente.
Nelle coda è definito il parametro Message TTL con un valore ad esempio di 604800000 (millisecondi) pari a 7 giorni, per cui tutti i messaggi pubblicati al suo interno rimarranno disponibili nella coda per 7 giorni, i messaggi più vecchi rimossi automaticamente.
Sistema di autenticazione e autorizzazione di RMAP¶
Il broker utilizza inoltre il sistema di autenticazione e autorizzazione di RMAP per autenticare la ricezione di messaggi:
fotografie: formato jpeg
configurazione stazioni: formato json
Questo metodo di uplodare foto e configurazioni eè per il momento da considerarsi obsoleto.
URL¶
Autentica utente o amministratore:
user_path "http://localhost/auth/user"
Sempre autorizzato tutti vhost:
vhost_path "http://localhost/auth/vhost"
Autorizzate risorse che iniziano con un punto "." e "configuration" o "photo":
resource_path "http://localhost/auth/resource"
Le successive verifiche di autenticazione vengono fatte dai daemon di importazione dati che verificano che l'utente utilizzato per l'autenticazione AMQP siano corrispondenti ai metadati dei dati inviati.
Per fotografie e configurazioni questa attualmente è una metodologia disattivata a vantaggio della metodologia HTTP.
Daemon¶
amqp2amqp_identvalidationd : valida gli ident per la pubblicazione dati da coda AMQP a coda AMQP
amqp2amqp_jsonline2bufrd : conversione da formato jsonline a bufr da coda AMQP a coda AMQP
amqp2arkimetd : archiviazione diretta da coda AMQP a arkimet (obsoleto)
amqp2dballed : archiviazione dati da coda AMQP a DBall.e; utilizza il lock per l'accesso in scrittura a DBall.e e le opzioni - -d DATALEVEL, --datalevel=DATALEVEL sample or report - -s STATIONTYPE, --stationtype=STATIONTYPE fixed or mobile quali delle 4 istanze eseguire
amqp2djangod : importazioni delle configurazioni stazione da coda AMQP a framework Django
amqp2geoimaged : importazione delle immagini georeferenziate da coda AMQP
amqp2mqttd : pubblica i dati da una coda AMQP al broker MQTT
Log¶
Tutti i log relativi ai daemon coinvolti in RMAP si trovano nella directory /var/log/rmap/.
Descrizione applicazioni Django¶
Il funzionamento del back-end e del front-end è garantito da una suite di applicazioni Django
stations app¶
Descrizione¶
Questa applicazione sovranintende alla gestione delle stazioni gestendone la crezione, configurazione e aggiornamento dei metadati, mantenedo aggiornati lo stato di funzionamento e autodiagnostica, le versioni del firmware utilizzate, e le informazioni di autenticazione e autorizzazione.
Espone l'interfaccia di amministrazione di Django tramite la quale è possibile fare operazioni particolari di amministrazione non ancora gestite da apposite funzioni da web.
Le stazioni si possono creare e modificare in vari modi:
tramite interfaccia web e template: ci sono un certo numero di configurazioni predefinite per stazioni standard che possono essere utilizzate modificando solo alcuni parametri specifici quali le coordinate, nme etc.
tramite linea di comando, tramite il tool rmap-config con una serie di passaggi è possibile creare da un template o definendo tutti i dettagli
tramite l'interfaccia admin di Django con una sequenza di operazioni è possibile creare e modificare una stazione; consigliato solo per modifiche
I template non sono altro che stazioni definite come tutte le altre con l'unica caratteristica nella Category:template ("used to generate new station") oltre a essere disattivate per non entrare negli elenchi delle stazioni "reali".
All'installazione vengono precaricate alcuni template tramite le fixture di Django; ad esempio: https://github.com/r-map/rmap/blob/master/python/rmap/stations/fixtures/template_stations_02.json
Le definizioni stazioni possono essere trasferite tra differenti istanze del server (server remoto e DB Django locale).
DataBase¶
table UserProfile¶
relazione one to one con l'oggetto User del Django authentication system utilizzato per estendere i metadati di un utente.
table StationMetadata¶
Metadati principali di una stazione. Identificativi che compongono la chieve univoca per il DataBase dati:
ident: identificativo per stazioni mobili
lat/lon: coordinate
network: rete di stazioni omogenee a cui appartiene
Identificativi univoci per il DataBase dati:
user: utente
slug: identificativo sintetico della stazione
table StationConstantdata¶
Coppia btable,value che compongono i dati costanti di stazione.
table Board¶
Board (moduli) che fanno parte di una stazione. Una Board prevede uno o più transporti di comunicazione, uno o più sensori, uno stato di funzionamento e uno stato del firmware.
table Transport*¶
Definiscono i paramtri di comunicazione per ogni trasporto.
table Sensor¶
Sensori connessi a una board. Identificativi che compongono la chiave univoca per il DataBase dati:
level: livello rappresentativo delle misure
timernage: elaborazione statistica
Definisce il driver utilizzato per il bus che bisogna utilizzare per comunicare con il sensore insieme ad alcuni parametri per identificarlo e per comunicare con lui.
table SensorType¶
Definisce un tipo di sensore: il livello dei dati (sample o report) e il tipo che determina il driver da utilizzare per comunicare con il sensore. Ogni sensore può riportare più misure definite dalla tabelle btable.
table Btable¶
Elenco dei Bcode della tabella B definita in modo univoco dalle specifiche RMAP (tabella B WMO). Fa parte delle chiavi univoche del DB dati. Sono abbinati descrizione e unità di misura prima e dopo un eventuale applicazione dei fattori di scala.
table BoardMaintStatus¶
Definisce lo stato di una Board così come comunicati dalla stazione (Stima V4). Prevede valori booleani e numerici.
table BoardFirmwareMetadata¶
Mantiene uno stato aggiornato dei firmware delle board presenti in stazione. Il campo mac viene utilizzato:
valorizzato al primo tentativo di aggiornamento
verificato i successivi aggiornamenti
i restanti campi sono aggiornati solo se la verifica ha successo
questo serve come semplice metodo di autenticazione della richiesta http di aggiornamento del firmware delle board. Se l'hardware viene cambiato a una stazione preesistente il mac deve essere resettato.
table StationMaintStatus¶
Questa tabella viene aggiornata tramite la messaggistica a standard RMAP nel root topic "maint" dei dati pubblicati MQTT. Mantiene la versione del firmware di stazione (versione globale, solitamente della board master), l'utimo aggiornamento della connessione e lo stato della connessione.
table StationImage¶
Associa ad ogni stazione delle fotografie con commenti e metadati utili per dettagliare la sua collocazione e caratteristiche.
URL¶
Sono riportate solo le versioni delle URL con tutti i parametri, anche omittibili
'^$' home page
'^wizard/$' wizard inizio configurazione stazione BASE (solo su stazione BASE)
'^wizard2/$' wizard seconda pagina configurazione stazione BASE (solo su stazione BASE)
'^wizard_done/$' wizard fine configurazione stazione BASE (solo su stazione BASE)
'^wizard_error/$' wizard errore configurazione stazione BASE (solo su stazione BASE)
'^admin/doc/' documentatione admin di Django
^admin/' admin di Django
'^auth/user' autenticazione/autorizzazione rabbit-mq; guarda amqp
'^auth/vhost' autenticazione/autorizzazione rabbit-mq; guarda amqp
'^auth/resource' autenticazione/autorizzazione rabbit-mq; guarda amqp
'^auth/auth$' autenticazione/autorizzazione mosqtto; guarda mqtt
'^auth/auth_sha$' autenticazione/autorizzazione mosquitto; guarda mqtt
'^auth/sha$' autenticazione/autorizzazione mosquitto; guarda mqtt
'^auth/pskkey$' autenticazione/autorizzazione mosquitto; guarda mqtt
'^auth/superuser$' autenticazione/autorizzazione mosquitto; guarda mqtt
'^auth/acl$' autenticazione/autorizzazione mosquitto; guarda mqtt
'^accounts/profile/(?P<mystation_slug>[-w]+)/(?P<stationimage_id>[-w]+)/$' pagina di amministrazione dell'utente/della stazione utente
'^robots.txt$' robots.txt per i motori di ricerca
'^stations/(?P<user>[-_w]+)/(?P<slug>[-_w]+)/$' elenco stazioni con metadati riassuntivi
'^stationstatus/(?P<user>[-_w]+)/(?P<slug>[-_w]+)/$' elenco stazioni con stato e autodiagnostica
'^stationmqttmonitor/(?P<user>[-_w]+)/(?P<slug>[-_w]+)/$' monitoraggio web della comunicazione MQTT
'^stationsupload/json/$' upload della configurazione stazione se l'utente è autenticato e se la stazione uplodata corrisponde all'utente stesso (è il metodo attualmente utilizzato in sostituzione di AMQP)
'^stationconfig/(?P<user>[-_w]+)/(?P<station_slug>[-_w]+)$' serie di RPC per configurare una stazione in modalità "notification"
'^stations/(?P<user>[-_w]+)/(?P<station_slug>[-_w]+)/json/$' configurazione stazione in formato json; se l'utente è autenticato il json è completo di password, nel caso contrario sono assenti; il timerange viene completato con P2=mqttsampletime; da utilizzare per la configurazione stazione
'^stations/(?P<user>[-_w]+)/(?P<station_slug>[-_w]+)/json_dump/$' dump della configurazione stazione in formato json; se l'utente è autenticato il json è completo di password, nel caso contrario sono assenti; il timerange non viene completato lasciando P2 per essere completato successivamente.
'^stations/(?P<user>[-_w]+)/(?P<station_slug>[-_w]+)/configv3/$' restituisce un file binario da utilizzare su SD card per la configurazione stazioni Stima V3
'^stations/(?P<user>[-_w]+)/(?P<station_slug>[-_w]+)/(?P<board_slug>[-_w]*)/json/$' configurazione di una board di una stazione in formato json; se l'utente è autenticato il json è completo di password, nel caso contrario sono assenti; il timerange viene completato con P2=mqttsampletime; da utilizzare per la configurazione stazione
'^delstation/(?P<user>[-_w]+)/(?P<slug>[-_w]+)/$' cancellazione di una stazione
'^stationlocaldata/(?P<user>[-_w]+)/(?P<slug>[-_w]+)/$' visualizza i dati misurati dalla stazione StimaWiFi se risulta collegata nella stessa rete locale con avahi/bonjour
'^stationsonmap/(?P<user>[-_w]+)/(?P<slug>[-_w]+)/$' visualizza le stazioni su mappa
Tools¶
rmap-configure
Esempio di configurazione di una stazione Stima V4
rmap-configure --wizard --station_slug teststation --stationname Stima V4 test station --username myuser --password password --server test.rmap.cc --lat 45.54321 --lon 12.54321 --height 234 --mqttrootpath report --mqttmaintpath maint --network test
rmap-configure --addboard --boardtype 11 --serialactivate --mqttactivate --tcpipactivate --canactivate --tcpipntpserver it.pool.ntp.org --tcpipname stima --tcpipgsmapn internet.wind --tcpippppnumber *99***1# --station_slug teststation --board_slug masterv4 --username myuser --server test.rmap.cc --mqttuser myuser --mqttpassword h23jhjhjh --mqttpskkey 1BF19DC005FFCE9277B4CFC696410426 --mqttsamplerate 900 --cannodeid 100 --cansubject node.master --cansubjectid 100 --cansamplerate 60
rmap-configure --addsensors_by_template none --station_slug teststation --board_slug masterv4 --username myuser
rmap-configure --addboard --boardtype 21 --serialnumber 0xABCDEF1 --serialactivate --canactivate --station_slug teststation --board_slug module_th --username myuser --cannodeid 60 --cansubject node.th --cansubjectid 60 --cansamplerate 60
rmap-configure --addsensors_by_template stima4_report_th --station_slug teststation --board_slug module_th --username myuser
rmap-configure --addboard --boardtype 20 --serialnumber 0xABCDEF2 --serialactivate --canactivate --station_slug teststation --board_slug module_rain --username myuser --cannodeid 61 --cansubject node.p --cansubjectid 61 --cansamplerate 60
rmap-configure --addsensors_by_template stima4_report_p --station_slug teststation --board_slug module_rain --username myuser
rmap-configure --addboard --boardtype 25 --serialnumber 0xABCDEF3 --serialactivate --canactivate --station_slug teststation --board_slug module_wind --username myuser --cannodeid 62 --cansubject node.wind --cansubjectid 62 --cansamplerate 60
rmap-configure --addsensors_by_template stima4_report_w --station_slug teststation --board_slug module_wind --username myuser
rmap-configure --addboard --boardtype 26 --serialnumber 0xABCDEF4 --serialactivate --canactivate --station_slug teststation --board_slug module_radiation --username myuser --cannodeid 63 --cansubject node.rad --cansubjectid 63 --cansamplerate 60
rmap-configure --addsensors_by_template stima4_report_r --station_slug teststation --board_slug module_radiation --username myuser
rmap-configure --addboard --boardtype 28 --serialnumber 0xABCDEF5 --serialactivate --canactivate --station_slug teststation --board_slug module_mppt --username myuser --cannodeid 64 --cansubject node.mppt --cansubjectid 64 --cansamplerate 60
rmap-configure --addsensors_by_template stima4_report_m --station_slug teststation --board_slug module_mppt --username myuser
rmap-configure --addboard --boardtype 29 --serialnumber 0xABCDEF6 --serialactivate --canactivate --station_slug teststation --board_slug module_svwc --username myuser --cannodeid 65 --cansubject node.svwc --cansubjectid 65 --cansamplerate 60
rmap-configure --addsensors_by_template stima4_report_s --station_slug teststation --board_slug module_svwc --username myuser
# configurazione tramite porta seriale
rmap-configure --config_station --station_slug teststation --username myuser --transport serial --device /dev/ttyACM0 --stima_version 4
# upload configurazione al server
#rmap-configure --upload_to_server --station_slug teststation --username myuser --password password --server test.rmap.cc
registration app¶
Descrizione¶
Se la funzione è abilitata da configurazione questa app gestisce la possibilità che gli utenti si registrino in modo sutonomo dovendo fornire come minimi una email.
DataBase¶
URL¶
'^registrazione/register/$' pagina di registrazione utenti
'^registrazione/' radice di tutti i path necessari per la registrazione utenti
'^registrazione/activate/complete/$'
'^registrazione/activate/resend/$'
'^registrazione/activate/(?P<activation_key>w+)/$'
'^registrazione/register/complete/$'
'^registrazione/register/closed/$'
'^registrazione/register/$'
'^registrazione/login/$'
'^registrazione/logout/$'
'^registrazione/password/change/$'
'^registrazione/password/change/done/$'
'^registrazione/password/reset/$'
'^registrazione/password/reset/complete/$'
'^registrazione/password/reset/done/$'
'^registrazione/password/reset/confirm/(?P<uidb64>[0-9A-Za-z_-]+)/(?P<token>.+)/$'
network app¶
Descrizione¶
Ogni stazione è associata a un network. In questa app viene visualizzata la lista dei network e i metadati di ogni network. Non esiste un link automatico tra i network pubblicati dalle stazioni e i network presenti in questa app. Se lo stesso network è presente sia nei dati che in questa app, i metadati presenti in questa app vengono visualizzati quando richiesto.
DataBase¶
URL¶
'^network/(?P<name>[-w]+)/$' navigazione e visualizzazione network
http2mqtt app¶
Descrizione¶
Questa app permette di pubblicare i dati tramite http. Le specifiche seguono le RMAP RFC per http con le specifiche a questo link http2mqtt
URL¶
'^http2mqtt/$'
firmware_updater e firmware_updater_stima app¶
Descrizione¶
firmware_updater: Versione per StimaWifi
Ogni firmware è caratterizzato da un nome e da una versione il nome è a piacere, la versione è una data parsabile da questo modulo python: https://dateutil.readthedocs.io/en/stable/parser.html
la richiesta può essere http o https, ma normalmente http.
Viene verificata la presenza di alcuni header nella richiesta http specifici per ESP8266/ESP32:
HTTP_USER_AGENT deve essere uguale a ESP8266-http-Update/ESP32-http-Update Se user-agent divers torna 403
HTTP_X_ESP8266_SKETCH_SIZE/HTTP_X_ESP32_SKETCH_SIZE deve essere impostato (ma non è utilizzato) altrimenti torna 403
X_ESP8266_AP_MAC/HTTP_X_ESP32_AP_MAC deve essere impostato (ma non è utilizzato) altrimenti torna 403
HTTP_X_ESP8266_FREE_SPACE/HTTP_X_ESP32_FREE_SPACE deve essere impostato (ma non è utilizzato) altrimenti torna 403
HTTP_X_ESP8266_SKETCH_MD5/HTTP_X_ESP32_SKETCH_MD5deve essere impostato (ma non è utilizzato) altrimenti torna 403
HTTP_X_ESP8266_CHIP_SIZE/HTTP_X_ESP32_CHIP_SIZEdeve essere impostato (ma non è utilizzato) altrimenti torna 403
HTTP_X_ESP8266_SDK_VERSION/HTTP_X_ESP32_SDK_VERSIONdeve essere impostato (ma non è utilizzato) altrimenti torna 403
X_ESP8266_STA_MAC/HTTP_X_ESP32_STA_MAC Essendo la richiesta d'aggiornamento del firmware non autenticata, la board dispone di un MAC che viene inviato nell'header X_ESP8266_STA_MAC il cui hash viene salvato la prima volta sul server e tutte le volte successive deve fare match per poter aggiornare le info sul server.
X-ESP8266-VERSION: l'header VERSION è codificata in json ad esempio: X-ESP8266-VERSION: {"ver":"2022-11-01T12:00:00"} - ver : versione attuale del firmware nel formato datetime ISO Nello stesso json possono essere inviati anche: - user (utente) - slug (station slug) - bslug (board slug)
nel qual caso sul server vengono aggiornate le informazioni relative alla board con versione inviata alla board per l'aggiornamento e la data e ora dell'invio (eventualmente utile per effettuare un commit dell'aggiornamento).
risposta:
Se il firmware non esiste torna 500
Se la versione non è corretta torna 300
Se non c'è un nuovo firmware torna 304
Se l'md5 del firmware attualmente running è uguale a quello dell'ultimo firmware disponibile torna 304
altrimenti risponde con il firmware con header 'x-MD5' pari all'md5 del firmware che segue
Il tutto si riassume con questa richiesta tramite curl:
curl --user-agent "ESP8266-http-Update" -H "X-ESP8266-STA-MAC:
1234" -H "X-ESP8266-AP-MAC: 1234" -H "X-ESP8266-FREE-SPACE: 1234" -H
"X-ESP8266-SKETCH-SIZE: 1234" -H "X-ESP8266-CHIP-SIZE: 1234" -H
"X-ESP8266-SDK-VERSION: 1234" -H "X-ESP8266-SKETCH-MD5: 1234" -H
'X-ESP8266-VERSION: {"ver":"2022-11-01T12:00:00"}'
"http://test.rmap.cc/firmware/update/stima4/" -v
URL¶
'^firmware/$'
'^firmware/update/(?P<name>[-_w]+)/$'
firmware_updater_stima: versione per Stima V4
HTTP_USER_AGENT deve essere uguale a STIMA4-http-Update Se user-agent divers torna 403
HTTP_X_STIMA4_BOARD_MAC Essendo la richiesta d'aggiornamento del firmware non autenticata, la board dispone di un MAC che viene inviato nell'header HTTP_X_STIMA4_BOARD_MAC il cui hash viene salvato la prima volta sul server e tutte le volte successive deve fare match per poter aggiornare le info sul server.
HTTP_X_STIMA4_VERSION l'header VERSION è codificata in json ad esempio: X_STIMA4_VERSION: {"version":4,"revision":5,"user":"userv4","slug":"stimav4","bslug":"stimacan1"} - version: versione attuale del firmware - revision: revisione attuale del firmware Nello stesso json possono essere inviati anche: - user: utente - slug: station slug - bslug: board slug
nel qual caso sul server vengono aggiornate le informazioni relative alla board con versione inviata alla board per l'aggiornamento e la data e ora dell'invio (eventualmente utile per effettuare un commit dell'aggiornamento).
risposta:
Se il firmware non esiste torna 500
Se la versione non è corretta torna 300
Se non c'è un nuovo firmware torna 304
altrimenti risponde con il firmware con header 'x-MD5' pari all'md5 del firmware che segue
URL¶
'^firmware/stima/v4/$'
'^firmware/stima/v4/update/(?P<name>[-_w]+)/$'
DataBase¶
Le due tabelle differiscono per la versionatura del firmware in un caso utilizzando un campo date e nell'altro revisione e versione.
geoimage app¶
Descrizione¶
Tramite interfaccia web è possibile inserire immagini georeferenziate, visualizzare anteprime sulla mappa, navigare le immagini su un sito nel tempo e cancellarle.
DataBase¶
URL¶
'^geoimage/geoimagesonmap/(?P<ident>[-_w]+)/$'
'^geoimage/geoimagebyid/(?P<id>[-_w]+)/$'
'^geoimage/geoimagedelete/(?P<id>[-_w]+)/$'
'^geoimage/geoimagesbycoordinate/(?P<lon>[-_w.]+)/(?P<lat>[-_w.]+)/$'
rpc app¶
Descrizione¶
Le stazioni possono eseguire Remote Procedure Call secondo le spscifiche; https://www.jsonrpc.org/specification e l'implementazione su MQTT in rmap rfc.
Ogni RPC è caratterizzata da un id incrementato in seuqenza per ogni stazione. Una RPC è attiva quando è solo stata richiesta, ma non ancora inviata tramite MQTT.
date corrisponde a quando è stata richiesta una RPC (stato sumbitted)
datecmd corrisponde a quando l'RPC è stata inviata tramite MQTT (stato running)
dateres corrisponde a quando è stata ricevuta una risposta (stato completed)
method : metodo della RPC
params : parametri della RPC
result : risultato della RPC
error : messaggio di errore
Una RPC assume quindi differenti stati: * submitted : è stata richiesta una RPC * running : l'RPC è stata inviata tramite MQTT * completed : è stata ricevuta una risposta
Lo stato submitted può essere attivato tramite interfaccia web o tool a linea di comando.
Da questo momento la gestione della RPC passa al daemon rpcd che periodicamente richiede al DB le RPC da gestire (stato submitted) e le invia alle stazioni tramite MQTT. Rimane poi sottoscritto al topic MQTT per la risposta che una volta ricevuta viene inserita in DB.
I tempi di esecuzione delle RPC possono essere molto lunghi vista caratteristica della connessione delle stazioni che non è permanente.
Se le stazioni non ricevono la richiesta di RPC o non inviano la riposta lo stato dell'RPC rimane "running".
L'interfaccia WEB che permette l'attivazione di una RPC ha due modalità: * modalità semplice che utilizza RPC predefinite:
reboot : riavvio stazione
reboot e firmware update : riavvio con eventuale firmware update del firmware precedentemente scaricato (solo Stima V4)
recovery last day of data : richiede reinvio dei dati delle ultime 24 ore
admin firmware download : richiede il download di un eventuale firmware più recente (solo Stima V4)
admin configuration download : richiede il download della configurazione stazione eventualmente aggiornata (solo Stima V4)
modalità a formato libero dove vengono richiesti:
metodo
parametri
DataBase¶
URL¶
'^rpcs/(?P<user>[-_w]+)/(?P<slug>[-_w]+)/$'
'^rpc/(?P<user>[-_w]+)/(?P<slug>[-_w]+)/(?P<id>[-_w]+)/$'
'^rpc-submit-free/(?P<user>[-_w]+)/(?P<slug>[-_w]+)/$'
'^rpc-submit/(?P<user>[-_w]+)/(?P<slug>[-_w]+)/$'
Daemon¶
rpcd : legge dal DB Django le eventuali RPC da eseguire inviandole tramite MQTT alle stazioni; Riceve le risposte e le inserisce nel DB Django
Tools¶
rmapctrl
--rpc_mqtt_admin_fdownload_v4 : invia richiesta RPC per un firmware download over MQTT per stazioni Stima V4 - --username=USERNAME : work on station managed by this username - --station_slug=STATION_SLUG : work on station defined by this slug
--purge_rpc : remove all non active RPC (submitted, running and completed)
--purge_rpc_completed : remove non active RPC and completed
ticket app¶
Descrizione¶
L'app gestisce i ticket relativi alle stazioni: * è relativo a una stazione * può essere attivo o no * può essere assegnato a più utenti (chi deve risolvere il problema) * più utenti possono essere abbonati (notifica delle modifiche) * possono essere associate immagini * possono essere associati allegati * a ogni ticket si susseguono azioni per risolverlo e poi disattivarlo
L'app non è completa e i ticket si possono inserire e gestire solo dall'interfaccia admin di Django. E' necessario aggiungere anche le notifiche tramite email
DataBase¶
URL¶
'^tickets/(?P<user>[-_w]+)/(?P<slug>[-_w]+)/$'
'^ticket/(?P<ticket>[-_w]+)/$'
'^ticket_image/(?P<image_id>[-_w]+)/$'
'^ticket_attachment/(?P<attachment_id>[-_w]+)/$'
'^tickets_assigned/(?P<user_ass>[-_w]+)/$'
'^tickets_subscribed/(?P<user_sub>[-_w]+)/$'
borinud app¶
Descrizione¶
Borinud mette a disposizioni delle API WEB per il download dei dati. Le fonti dei dati possono essere differenti e multiple: DBall.e e Arkimet. Oltre ai database utilizza gli explorer per mantenere aggiornati e veloci i cataloghi dei dati presenti.
URL¶
basepattern = ('^borinud/api/v1/(?P<format>\w+)'
'/(?P<ident>\w+|\*|-)'
'/(?P<coords>(?P<lon>\-?\+?\d+|-),(?P<lat>\-?\+?\d+|-)|\*)'
'/(?P<network>[-\w]+|\*)'
'/(?P<trange>(?P<tr>\d+|-|\*),(?P<p1>\d+|-|\*),(?P<p2>\d+|-|\*)|\*)'
'/(?P<level>(?P<lt1>\d+|-|\*),(?P<lv1>\d+|-|\*),(?P<lt2>\d+|-|\*),(?P<lv2>\d+|-|\*)|\*)'
'/(?P<var>B\d{5}|\*)')
'^borinud/$'
basepattern + '/summaries/(?P<year>d{4})/(?P<month>d{2})/(?P<day>d{2})$'
basepattern + '/timeseries/(?P<year>d{4})/(?P<month>d{2})/(?P<day>d{2})/(?P<hour>d{2})$'
basepattern + '/spatialseries/(?P<year>d{4})/(?P<month>d{2})/(?P<day>d{2})/(?P<hour>d{2})$'
basepattern + '/stationdata$'
basepattern + '/stations$'
Tools¶
rmap-explorer: viene eseguito in crontab per aggiornare gli explorer di DBall.e in /rmap/dballe
dballe2arkimet : oltre a trasferire i dati da DBall.e a arkimet aggiorna gli explorer di arkimet in /rmap/arkimet. L'aggiornamento degli explorer di arkimet avviene in modo incrementale ogni volta che si aggiunge un blocco dati a Arkimet. Se dovesse avvenire un disallineamento o un intervento manuale sul DB è possibile ricreare gli explorer di Arkimet tramite questo script:
#!/usr/bin/python3
import dballe
from pathlib import Path
dstypes=["report_fixed","report_mobile","sample_fixed","sample_mobile"]
for dstype in dstypes:
for path in Path(dstype).rglob('*.bufr'):
file=path.as_posix()
print(file)
# update from file
with dballe.Explorer(dstype+".json") as explorer:
with explorer.update() as updater:
importer = dballe.Importer("BUFR")
with importer.from_file(file) as message:
try:
updater.add_messages(message)
except Exception as e:
print (e)
print ("updated from file")
#print (explorer.all_reports)
#print (explorer.all_levels)
#print (explorer.all_tranges)
#print (explorer.all_varcodes)
print (explorer.stats)
graphite-dballe app¶
Descrizione¶
Questa app è una versione embedded di graphite che utilizza borinud come storage-backends
URL¶
Consultare la documentazione.
insertdata app¶
Descrizione¶
TODO
URL¶
'^insertdata/image$'
'^insertdata/manualdata$'
'^insertdata/newstation$'
'^insertdata/stationmodify/(?P<slug>[-_w]+)/(?P<bslug>[-_w]+)/$'
showdata app¶
Descrizione¶
TODO
URL¶
basepattern = (
'^showdata/(?P<ident>\w+|\*|-)'
'/(?P<coords>(?P<lon>\-?\+?\d+|-),(?P<lat>\-?\+?\d+|-)|\*)'
'/(?P<network>[-\w]+|\*)'
'/(?P<trange>(?P<tr>\d+|-|\*),(?P<p1>\d+|-|\*),(?P<p2>\d+|-|\*)|\*)'
'/(?P<level>(?P<lt1>\d+|-|\*),(?P<lv1>\d+|-|\*),(?P<lt2>\d+|-|\*),(?P<lv2>\d+|-|\*)|\*)'
'/(?P<var>B\d{5}|\*)')
'^showdata/$'
basepattern + '/timeseries/(?P<year>d{4})/(?P<month>d{2})/(?P<day>d{2})/(?P<hour>d{2})$'
basepattern + '/spatialseries/(?P<year>d{4})/(?P<month>d{2})/(?P<day>d{2})$'
basepattern + '/stationdata$'
basepattern + '/stations$'
Daemon¶
Il daemon hanno i seguento comandi: * run : esegue nel terminale * start : esegue come daemon * stop : termina l'esecuzione del daemon
le altre opzioni sono documentate con l'opzione --help. Qui una sintesi di funzionalità e opzioni:
I daemon specifici per una app sono stati descritti precedentemente nella apposizta sezione della app.
mqtt2amqpd :
-d DATALEVEL, --datalevel=DATALEVEL : sample or report
-s STATIONTYPE, --stationtype=STATIONTYPE : fixed or mobile
-u --nouserasident : do not use user as ident for fixed station too (default use ident)
conversione dei dati da RMAP over MQTT a formato bufr e messaggio AMQP; sono necessarie 4 istanze per differenti datalevel e stationtype. ; l'opzione --nouserasident decide il tipo di conversione da effettuare: se lo user è utilizzato come ident i dati prodotti saranno utili per la visualizzazione dentro il server RMAP, ma formalmente scorretti; se l'opzione è attivata i dati prodotti saranno formalmente corretti e scambiali internazionalmente. E' possibile attivare 8 istanze: 4 per l'archiviazione locale e 4 per la distribuzione oppure le prima 4 nella data ingestion e le altre 4 nel backend.
mqtt2stationmaintd : preleva i messaggi diagnostici pubblicati dalle stazioni in MQTT e li inserisce in archivio Django
composereportd : effettua le elaborazioni necessarie per calcolare i report a partire dai sample; ad esempio esegue le medie ogni 15', calcola valori minimi e massimi, dopo aver calcolato le osservazioni da campionamenti. Legge e scrive da DBall.e sample_fixed a DBall.e report_fixed
mqtt2dballed : conversione diretta da RMAP over MQTT a DBall.e (obsoleta)
mqtt2graphited : conversione da RMAP over MQTT agli archivi specifici di graphite (obsoleta)
stationd: daemon che effettua le misure e le elabora, le invia da una stazione di misura basata su Linux/Python (obsoleta)
ttn2dballed : daemon che effettua la traslazione da dati pubblicati tramite LoraWan TTN a MQTT RMAP (obsoleta)
Tools¶
I tools specifici per una app sono stati descritti precedentemente nella apposizta sezione della app.
Altri tools disponibili sono:
rmapgui : esegue la app interattiva tramite libreria Kivy per dispositivi touch
rmapweb : esegue un server http senza necessità di apache
rmapctrl : esegue comandi inizializzazione e mantenimento del sistema RMAP - --syncdb : initialize rmap DB (default False) - --collectstatic : Collect static files from multiple apps into a single path (default False) - --dumpdata : dump Data Base (default False) - --loaddata=LOADDATA : restore Data Base (default none)
rmap-explorer per generare gli explorer dei DB DBall.e e accelerare i summary - rmap-explorer --write --type report_fixed - rmap-explorer --write --type report_mobile - rmap-explorer --write --type sample_fixed - rmap-explorer --write --type sample_mobile
dballe2arkimet : permette la migrazione dei dati ormai "stabilizzati" da DBall.e a Arkimet: utilizza il lock per l'accesso in scrittura a DBall.e
rmap-manage : comandi per il sistema Django
Configurazione¶
TODO
Operazioni per l'aggiornamento¶
TODO
Operazioni periodiche di manutenzione¶
TODO
Struttura cartelle¶
- arduino
obsolete library and formware for arduino SDK
- arpae_aq_ckan_to_bufr
getter and importer from ARPAE ckan db for air quality data
- doc
documentation source
- fritzing
simple schematic and PCB for fritzing EDA
- kicad
all Stima schematic and PCB for Kicad
- luftdaten_to_bufr
getter and importer from luftdaten DB
- mqtt2bufr
mqtt to bufr and vice versa following RMAP specification
- pic
obsolete firmware for i2c-power pic version
- pipe2dba
osolete importer from pipe
- platformio
all Stima firmware project for platformio
- python
python source code for RMAP server and tools
- rabbitmq
saved configuration for rabbitmq broker
- raspberry
obsolete software for Stima base raspberry version
- rpm
rpm spec files to be updated
- server
configuration files for RMAP server full version (changed from default installation)
- server-backend
configuration files for RMAP server backend only version (changed from default installation)
- server-data-ingestion
configuration files for RMAP server data-ingestion only version (changed from default installation)
Installazione server completo basato su Rocky Linux 8¶
Installazione sistema operativo¶
Installare Rocky Linux 8.
Aggiunta repository e installazione pacchetti
dnf -y install epel-release
dnf -y install yum-plugin-copr
dnf -y copr enable simc/stable
dnf -y copr enable pat1/rmap
dnf -y config-manager --set-enabled powertools
dnf -y copr enable simc/cosudo
dnf -y install python3-rmap
dnf -y install python3-django-dynamic-map-borinud
dnf -y install mosquitto mosquitto-auth-plug
dnf -y install arkimet dballe
dnf -y install stunnel
useradd rmap
/etc/selinux/config:
SELINUX=disabled
mkdir /rmap
chmod go+rx /rmap
mkdir /var/log/rmap
chown -R rmap:rmap /var/log/rmap
Generate ssl auto signed certificate
mkdir certs
cd certs
1 – Since we don’t have a certificate authority, we’ll create a local CA using SSL:
openssl genrsa -des3 -out ca.key 2048
enter a pass phrase with at least 4 characters. Remember it as it will be used several times.
2 – Then we’ll create a signing request for our local CA
openssl req -new -key ca.key -out ca.csr -sha256
Enter the same passphrase chosen in the previous step. It’s safe to leave all other fields empty, for the sake of our setup’s simplicity.
3 – Then we can create our CA root certificate, valid for 180 days:
openssl x509 -req -in ca.csr -signkey ca.key -out ca-root.crt -days 180 -sha256
Again, enter the preciously chosen passphrase when requested to do so
4 – We’ll then create our certificate key
openssl genrsa -out localhost.key 2048
5 – And using the key, we’ll create a certificate request:
openssl req -new -key localhost.key -out localhost.csr -sha256
Note: when being prompted for the “Common Name”, use “localhost”, as this will be the way we’ll reference the MQTT broker locally.
If you have a DNS entry pointing to the host server, you can use that too. All remaining fields can be left empty.
6 – Lastly, we’ll create the certificate, using the certificate request created in step 5 and the CA root certificate created in step 5, also valid for 180 days
openssl x509 -req -in mosquitto.csr -CA ca-root.crt -CAkey ca.key -CAcreateserial -out localhost.crt -days 180
When you’re done you should have the following files in the directory:
ca-root.crt – Certificate authority root certificate
ca.csr – Certificate authority certificate signing request
ca.key – Certificate Authority certificate Key
localhost.crt – Mosquitto certificate
localhost.csr – Mosquitto certificate signing request
localhost.key – Mosquitto certificate key
Firewall¶
dnf -y install firwalld
systemctrl enable firewalld
systemctrl start firewalld
firewall-cmd --permanent --zone=public --add-port=80/tcp
firewall-cmd --permanent --zone=public --add-port=442/tcp
firewall-cmd --permanent --zone=public --add-port=443/tcp
firewall-cmd --permanent --zone=public --add-port=5925/tcp
firewall-cmd --permanent --zone=public --add-port=1883/tcp
firewall-cmd --permanent --zone=public --add-port=5671/tcp
firewall-cmd --permanent --zone=public --add-port=5672/tcp
firewall-cmd --permanent --zone=public --add-port=8883/tcp
firewall-cmd --permanent --zone=public --add-port=8884/tcp
firewall-cmd --permanent --zone=public --add-port=15672/tcp
firewall-cmd --reload
postgresql¶
dnf module disable postgresql:10
dnf module enable postgresql:12
dnf install postgresql-server postgresql-contrib python3-psycopg2
mkdir /etc/systemd/system/postgresql.service.d/
/etc/systemd/system/postgresql.service.d/rmap.conf
mkdir /rmap/pgsql/
chown postgres:postgres /rmap/pgsql/
postgresql-setup --initdb --unit postgresql
/rmap/pgsql/data/postgresql.conf
systemctl enable postgresql.service
systemctl start postgresql.service
su - postgres
createuser -P -e rmapadmin
< insert rmapadmin as password >
createdb --owner=rmapadmin rmapadmin
exit
rmapctrl --syncdb
su - postgres
createuser -P -e rmap
< insert rmap as password >
createdb --owner=rmap report_fixed
createdb --owner=rmap report_mobile
createdb --owner=rmap sample_fixed
createdb --owner=rmap sample_mobile
exit
dbadb wipe --dsn="postgresql://rmap:<password>@localhost/report_fixed"
dbadb wipe --dsn="postgresql://rmap:<password>@localhost/report_mobile"
dbadb wipe --dsn="postgresql://rmap:<password>@localhost/sample_mobile"
dbadb wipe --dsn="postgresql://rmap:<password>@localhost/sample_fixed"
apache¶
Collect static files from django apps:
mkdir /root/global_static
rmapctrl --collectstatic
rmdir /root/global_static
- ::
dnf install python3-mod_wsgi dnf install mod_security mod_security_crs dnf install mod_ssl
- ::
useradd -r rmap mkdir /home/rmap chown rmap:rmap /home/rmap mkdir /rmap/cache chown rmap:rmap /rmap/cache mkdir /usr/share/rmap/media chown rmap:rmap /usr/share/rmap/media
cp -r ~/certs /etc/httpd chown -R apache /etc/httpd/certs
/etc/httpd/conf.modules.d/00-mpm.conf
/etc/httpd/modsecurity.d/crs-setup.conf
/etc/httpd/modsecurity.d/local_rules/modsecurity_localrules.conf
chkconfig httpd on
service httpd start
Stunnel¶
Create file with psk keys:
rmapctrl --exportmqttpsk > /etc/stunnel/file.psk
/etc/cron.d/stunnel_presharedkey
chkconfig stunnel on
service stunnel start
Arkimet¶
dnf install arkimet arkimet-postprocessor-suite
useradd -r arkimet
mkdir /home/arkimet
chown arkimet:arkimet /home/arkimet
mkdir /rmap/arkimet/
chown -R arkimet:rmap /rmap/arkimet/
chmod -R g+w /rmap/arkimet/
oppure:
chown -R rmap:rmap /rmap/arkimet/
mkdir /var/log/arkimet
chown -R arkimet:arkimet /var/log/arkimet
/etc/arkimet/scan/bufr_generic_mobile_rmap.py
Replicate structure in:
systemctl daemon-reload
chkconfig arkimet on
service arkimet start
Mosquitto¶
mkdir /etc/mosquitto/conf.d
mkdir /rmap/mosquitto
chown mosquitto:mosquitto /rmap/mosquitto
/etc/mosquitto/conf.d/rmap.conf
remove everythings and add in /etc/mosquitto/mosquitto.conf
include_dir /etc/mosquitto/conf.d
pid_file /var/run/mosquitto/mosquitto.pid
cp -r ~/certs /etc/mosquitto/
chown -R mosquitto /etc/mosquitto/certs
touch /etc/mosquitto/pwfile
chkconfig mosquitto on
service mosquitto start
Rabbitmq¶
curl -s https://packagecloud.io/install/repositories/rabbitmq/rabbitmq-server/script.rpm.sh |bash
curl -s https://packagecloud.io/install/repositories/rabbitmq/erlang/script.rpm.sh | sudo bash
dnf install rabbitmq-server
/etc/rabbitmq/rabbitmq-env.conf
cp -r ~/certs /etc/rabbitmq/
chown -R rabbitmq /etc/rabbitmq/certs
mkdir -p /rmap/rabbitmq/mnesia/
chown -R rabbitmq:rabbitmq /rmap/rabbitmq
chkconfig rabbitmq-server on
service rabbitmq-server start
login at management interface with user "guest" and password "guest" on overview page use import definition to configure exchange, queue and users with the same management interface remove "guest" user and login with a new real user
Per attivare uno showell:
rabbitmqctl set_parameter shovel report_mobile '{"src-protocol": "amqp091", "src-uri": "amqp://rmap:<password>@rmap.cc", "src-queue": "report_mobile_saved", "dest-protocol": "amqp091", "dest-uri": "amqp://rmap:<password>@", "dest-queue": "report_mobile"}'
problema non risolto: se si trasferiscono dati scritti da un utente autenticandosi con un altro utente la security su user_id lo vieta. https://www.rabbitmq.com/shovel-dynamic.html bisognerebbe riuscire a settare "user_id" tramite il parametro "dest-publish-properties" nel formato json sopra ma non funziona
Cron¶
mkdir /rmap/dballe
chown -R rmap:rmap /rmap/dballe
Opzionali per provider esterni con appositi convertitori:
Sincronizzazione DB da un server¶
Server di origine¶
rmapctrl --dumpdata > dumpdata.json
rimuovere le prime righe che non sono json
dbadb export --dsn="mysql:///report_fixed?user=rmap&password=****" > report_fixed.bufr
dbadb export --dsn="mysql:///report_mobile?user=rmap&password=****" > report_mobile.bufr
dbadb export --dsn="mysql:///sample_fixed?user=rmap&password=****" > sample_fixed.bufr
dbadb export --dsn="mysql:///sample_mobile?user=rmap&password=****" > sample_mobile.bufr
Server di destinazione¶
Da interfaccia web admin rimuovere TUTTI gli utenti (compreso rmap)
rmapctrl --loaddata=dumpdata.json
dbadb import --wipe-first --dsn="postgresql://rmap:***@localhost/report_fixed" report_fixed.bufr
dbadb import --wipe-first --dsn="postgresql://rmap:***@localhost/report_mobile" report_mobile.bufr
dbadb import --wipe-first --dsn="postgresql://rmap:***@localhost/sample_mobile" sample_mobile.bufr
dbadb import --wipe-first --dsn="postgresql://rmap:***@localhost/sample_fixed" sample_fixed.bufr
cd /usr/share/rmap/
rsync -av utente@serverorigine:/usr/share/rmap/media .
Arkiweb¶
AL MOMENTO NON DISPONIBILE !
dnf install arkiweb
/etc/httpd/conf.d/arkiweb.conf
ScriptAlias /services/arkiweb/ /usr/lib64/arkiweb/
Alias /arkiweb /var/www/html/arkiweb
<Directory "/usr/lib64/arkiweb">
AllowOverride None
Options +ExecCGI
Order allow,deny
Allow from all
# ARKIWEB_CONFIG is mandatory!
SetEnv ARKIWEB_CONFIG /rmap/arkimet/arkiweb.config
Require all granted
# Authentication (optional)
#
# Basic authentication example:
# SetEnv ARKIWEB_RESTRICT REMOTE_USER
# AuthType Basic
# AuthUserFile /etc/arkiweb.passwords
# require valid-user
</Directory>
Alias /arkiwebjs/ /usr/share/arkiweb/public/
<Directory "/usr/share/arkiweb/public">
#Require all granted
AllowOverride None
Order allow,deny
Allow from all
Require all granted
</Directory>
mkdir /var/www/html/arkiweb/
cp /usr/share/doc/arkiweb/html/example/index.html /var/www/html/arkiweb/index.html
/rmap/arkimet/arkiweb.config
Installazione server solo funzionalità DATA INGESTION basato su Rocky Linux 8¶
Installazione sistema operativo¶
Installare Rocky Linux 8.
Aggiunta repository e installazione pacchetti
dnf -y install epel-release
dnf install yum-plugin-copr
dnf copr enable simc/stable
dnf copr enable pat1/rmap
dnf config-manager --set-enabled powertools
dnf install python3-rmap-core
dnf install mosquitto mosquitto-auth-plug
useradd rmap
modificare il file /etc/selinux/config:
SELINUX=disabled
scaricare il file /etc/tmpfiles.d/rmap.conf
mkdir /rmap
chmod go+rx /rmap
mkdir /var/log/rmap
chown -R rmap:rmap /var/log/rmap
scaricare il file /etc/rmap/rmap-site.cfg
cambiare la password dell'utente amministratore.
Mosquitto¶
mkdir /etc/mosquitto/conf.d
mkdir /rmap/mosquitto
chown mosquitto:mosquitto /rmap/mosquitto
scaricare il file /etc/mosquitto/conf.d/rmap.conf
cancellare tutto il contenuto del file /etc/mosquitto/mosquitto.conf e sostituirlo con le seguenti righe:
include_dir /etc/mosquitto/conf.d
pid_file /var/run/mosquitto/mosquitto.pid
systemctl enable mosquitto
systemctl start mosquitto
Rabbitmq¶
curl -s https://packagecloud.io/install/repositories/rabbitmq/rabbitmq-server/script.rpm.sh |bash
curl -s https://packagecloud.io/install/repositories/rabbitmq/erlang/script.rpm.sh | sudo bash
dnf install rabbitmq-server
scaricare il file /etc/rabbitmq/enabled_plugins
scaricare il file /etc/rabbitmq/rabbitmq-env.conf
scaricare il file /etc/rabbitmq/rabbitmq.config
Installare il certificato ssl/tls per il dominio del server in:
/etc/arpaecert/arpae_it-rabbitmq.pem
/etc/arpaecert/arpae_it-mosquitto.pem
e impostare gli opportuni privilegi di lettura/scrittura.
-rw------- 1 mosquitto mosquitto 6849 1 dic 14.23 arpae_it-mosquitto.pem
-rw------- 1 rabbitmq rabbitmq 6849 20 nov 10.49 arpae_it-rabbitmq.pem
mkdir -p /rmap/rabbitmq/mnesia/
chown -R rabbitmq:rabbitmq /rmap/rabbitmq
systemctl enable rabbitmq-server
systemctl start rabbitmq-server
effettuare il login all'interfaccia di management web: <http://server-fqdn:15672/> con user "guest" e password "guest", quindi utilizzare la funzione "import definition" per caricare exchange, queue e users importando il seguente file:
rabbit_server_data_ingestion.json
dalla stessa interfaccia di management web impostare le password per tutti gli utenti, rimuovere l'utente "guest" e fare login con uno dei nuovi utenti definiti.
Monit¶
yum install monit
scaricare il file /etc/monitrc
scaricare il file /etc/monit.d/rmap
chmod 0700 /etc/monitrc /etc/monit.d/rmap
chown root:root /etc/monitrc /etc/monit.d/rmap
systemctl enable monit
systemctl start monit
Sincronizzazione file statici per autenticazione e autorizzazione da un server RMAP backend¶
Server di origine¶
rmapctrl --exportsha > file.pwd
rmapctrl --exportmqttsha >> file.pwd
rmapctrl --exportmqttacl > aclfile
rmapctrl --exportmqttpsk > file.psk
eventualmente rimuovere le prime righe di messaggistica del logging
Server di destinazione¶
Trasferire i file in /etc/mosquitto/ sul nostro server per la data ingestion. Imparire il comando:
/bin/systemctl reload mosquitto.service
Installazione server RMAP solo funzionalità BACKEND basato su Rocky Linux 8 (a seervizio per la data ingestion su un'altra macchina)¶
Questi file sono specializzati per un server di solo backend:
/etc/httpd/modsecurity.d/crs-setup.conf
In questi due file sostituire la stringa <insert IP of data-ingestion machine> con quanto indicato.
Servizi¶
Disabilitare mosquitto.