mirror of
https://git.rwth-aachen.de/acs/public/villas/node/
synced 2025-03-30 00:00:11 +01:00
first chunk of NGSI node type implementation
This commit is contained in:
parent
006440567a
commit
c63ad04400
5 changed files with 287 additions and 0 deletions
|
@ -4,6 +4,7 @@
|
||||||
@subpage opal
|
@subpage opal
|
||||||
@subpage file
|
@subpage file
|
||||||
@subpage socket
|
@subpage socket
|
||||||
|
@subpage ngsi
|
||||||
|
|
||||||
Every server needs clients which act as sinks / sources for simulation data. In case of S2SS these clients are called _nodes_.
|
Every server needs clients which act as sinks / sources for simulation data. In case of S2SS these clients are called _nodes_.
|
||||||
|
|
||||||
|
@ -13,5 +14,6 @@ Take a look at the `clients/` directory for them:
|
||||||
- RTDS via GTFPGA and PCIexpress
|
- RTDS via GTFPGA and PCIexpress
|
||||||
- OPAL via Asynchronous Process and UDP
|
- OPAL via Asynchronous Process and UDP
|
||||||
- OPAL via Asynchronous Process and Shared memory
|
- OPAL via Asynchronous Process and Shared memory
|
||||||
|
- NGSI 9/10 (FIRWARE context broker)
|
||||||
- Labview (*planned*)
|
- Labview (*planned*)
|
||||||
- Simulink (*planned*)
|
- Simulink (*planned*)
|
||||||
|
|
|
@ -111,6 +111,21 @@ nodes = {
|
||||||
id = "1ab8:4005", # The PCIe vendor:device ID (see third column in 'lspci -n' output)
|
id = "1ab8:4005", # The PCIe vendor:device ID (see third column in 'lspci -n' output)
|
||||||
|
|
||||||
rate = 1
|
rate = 1
|
||||||
|
},
|
||||||
|
ngsi_node = {
|
||||||
|
type = "ngsi",
|
||||||
|
|
||||||
|
### The following settings are specific to the gtfpga node-type!! ###
|
||||||
|
endpoint = "http://46.101.131.212:1026/v1", # The HTTP / REST endpoint of the FIRWARE context broker
|
||||||
|
|
||||||
|
mapping = [ # Format: "entityID(entityType).AttributeId(AttributeType)"
|
||||||
|
"rtds_sub1(voltage3).v1(float),
|
||||||
|
"rtds_sub1(voltage3).v2(float)",
|
||||||
|
"rtds_sub1(voltage3).v3(float)",
|
||||||
|
"rtds_sub2(power3).p1(float)",
|
||||||
|
"rtds_sub2(power3).p2(float)",
|
||||||
|
"rtds_sub2(power3).p3(float)"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
86
server/include/ngsi.h
Normal file
86
server/include/ngsi.h
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
/** Node type: NGSI 9/10 (FIWARE context broker)
|
||||||
|
*
|
||||||
|
* This file implements the NGSI protocol as a node type.
|
||||||
|
*
|
||||||
|
* @see https://forge.fiware.org/plugins/mediawiki/wiki/fiware/index.php/FI-WARE_NGSI-10_Open_RESTful_API_Specification
|
||||||
|
* @file
|
||||||
|
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||||
|
* @copyright 2014-2015, Institute for Automation of Complex Power Systems, EONERC
|
||||||
|
* This file is part of S2SS. All Rights Reserved. Proprietary and confidential.
|
||||||
|
* Unauthorized copying of this file, via any medium is strictly prohibited.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @addtogroup ngsi FIRWARE NGSI 9/10 RESTful HTTP API
|
||||||
|
* @ingroup node
|
||||||
|
* @{
|
||||||
|
**********************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _NGSI_H_
|
||||||
|
#define _NGSI_H_
|
||||||
|
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
#include "list.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "msg.h"
|
||||||
|
#include "cfg.h"
|
||||||
|
#include "node.h"
|
||||||
|
|
||||||
|
struct node;
|
||||||
|
|
||||||
|
struct ngsi_attribute {
|
||||||
|
char *name;
|
||||||
|
char *type;
|
||||||
|
|
||||||
|
int index;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ngsi_entity {
|
||||||
|
char *name;
|
||||||
|
char *type;
|
||||||
|
|
||||||
|
struct list attributes;
|
||||||
|
struct list metadata;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ngsi {
|
||||||
|
char *endpoint;
|
||||||
|
char *token;
|
||||||
|
|
||||||
|
struct list entities;
|
||||||
|
|
||||||
|
struct curl_slist *headers;
|
||||||
|
CURL *curl;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Initialize global NGSI settings and maps shared memory regions.
|
||||||
|
*
|
||||||
|
* @see node_vtable::init
|
||||||
|
*/
|
||||||
|
int ngsi_init(int argc, char *argv[], struct settings *set);
|
||||||
|
|
||||||
|
/** Free global NGSI settings and unmaps shared memory regions.
|
||||||
|
*
|
||||||
|
* @see node_vtable::deinit
|
||||||
|
*/
|
||||||
|
int ngsi_deinit();
|
||||||
|
|
||||||
|
/** @see node_vtable::parse */
|
||||||
|
int ngsi_parse(config_setting_t *cfg, struct node *n);
|
||||||
|
|
||||||
|
/** @see node_vtable::print */
|
||||||
|
int ngsi_print(struct node *n, char *buf, int len);
|
||||||
|
|
||||||
|
/** @see node_vtable::open */
|
||||||
|
int ngsi_open(struct node *n);
|
||||||
|
|
||||||
|
/** @see node_vtable::close */
|
||||||
|
int ngsi_close(struct node *n);
|
||||||
|
|
||||||
|
/** @see node_vtable::read */
|
||||||
|
int ngsi_read(struct node *n, struct msg *pool, int poolsize, int first, int cnt);
|
||||||
|
|
||||||
|
/** @see node_vtable::write */
|
||||||
|
int ngsi_write(struct node *n, struct msg *pool, int poolsize, int first, int cnt);
|
||||||
|
|
||||||
|
#endif /** _NGSI_H_ @} */
|
179
server/src/ngsi.c
Normal file
179
server/src/ngsi.c
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
/** Node type: FIWARE NGSI 9/10
|
||||||
|
*
|
||||||
|
* This file implements the NGSI protocol as a node type.
|
||||||
|
*
|
||||||
|
* @see https://forge.fiware.org/plugins/mediawiki/wiki/fiware/index.php/FI-WARE_NGSI-10_Open_RESTful_API_Specification
|
||||||
|
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||||
|
* @copyright 2014-2015, Institute for Automation of Complex Power Systems, EONERC
|
||||||
|
* This file is part of S2SS. All Rights Reserved. Proprietary and confidential.
|
||||||
|
* Unauthorized copying of this file, via any medium is strictly prohibited.
|
||||||
|
**********************************************************************************/
|
||||||
|
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include <jansson.h>
|
||||||
|
|
||||||
|
#include "ngsi.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
/* NGSI Entity, Attribute & Metadata structure */
|
||||||
|
|
||||||
|
void ngsi_entity_dtor(void *ptr)
|
||||||
|
{
|
||||||
|
struct ngsi_entity *entity = ptr;
|
||||||
|
|
||||||
|
list_destroy(&entity->attributes);
|
||||||
|
list_destroy(&entity->metadata);
|
||||||
|
|
||||||
|
free(entity->name);
|
||||||
|
free(entity->type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ngsi_attribute_dtor(void *ptr)
|
||||||
|
{
|
||||||
|
struct ngsi_attribute *entity = ptr;
|
||||||
|
|
||||||
|
free(entity->name);
|
||||||
|
free(entity->type);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ngsi_entity * ngsi_entity()
|
||||||
|
{
|
||||||
|
struct ngsi_entity *entity = alloc(sizeof(struct ngsi_entity));
|
||||||
|
|
||||||
|
list_init(&entity->attributes, ngsi_attribute_dtor);
|
||||||
|
list_init(&entity->metadata, ngsi_attribute_dtor);
|
||||||
|
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Node type */
|
||||||
|
|
||||||
|
int ngsi_init(int argc, char *argv[], struct settings *set)
|
||||||
|
{
|
||||||
|
curl_global_init(CURL_GLOBAL_ALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ngsi_deinit()
|
||||||
|
{
|
||||||
|
curl_global_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ngsi_parse(config_setting_t *cfg, struct node *n)
|
||||||
|
{
|
||||||
|
struct ngsi *i = n->ngsi;
|
||||||
|
|
||||||
|
config_setting_t *mapping = config_setting_get_member(cfg, "mapping");
|
||||||
|
if (!mapping || !config_setting_is_array(mapping))
|
||||||
|
cerror(cfg, "Missing entity.attribute mapping for node '%s", n->name);
|
||||||
|
|
||||||
|
for (int i = 0; i < config_setting_length(mapping); i++) {
|
||||||
|
const char *token = config_setting_get_string_elem(mapping, i);
|
||||||
|
if (token) {
|
||||||
|
if (sscanf(token, "%ms(%ms).%ms", &entity, &type, &attribue) != 2)
|
||||||
|
cerror(mapping, "Invalid entity.attribute token: '%s'", token);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
cerror(mapping, "Invalid entity.attribute token");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ngsi_print(struct node *n, char *buf, int len)
|
||||||
|
{
|
||||||
|
struct ngsi *i = n->ngsi;
|
||||||
|
|
||||||
|
return snprintf(buf, len, "endpoint=%s, token=%s, entities=%u",
|
||||||
|
i->endpoint, i->token, i->entities);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ngsi_open(struct node *n)
|
||||||
|
{
|
||||||
|
char buf[128];
|
||||||
|
struct ngsi *i = n->ngsi;
|
||||||
|
|
||||||
|
i->curl = curl_easy_init();
|
||||||
|
i->headers = NULL:
|
||||||
|
|
||||||
|
if (i->token) {
|
||||||
|
snprintf(buf, sizeof(buf), "Auth-Token: %s", i->token);
|
||||||
|
i->headers = curl_slist_append(i->headers, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
i->headers = curl_slist_append(i->headers, "User-Agent: S2SS " VERSION);
|
||||||
|
i->headers = curl_slist_append(i->headers, "Content-Type: application/json");
|
||||||
|
|
||||||
|
snprintf(buf, sizeof(buf), "%s/v1/%s")
|
||||||
|
|
||||||
|
curl_easy_setopt(i->curl, CURLOPT_URL, url);
|
||||||
|
curl_easy_setopt(i->curl, CURLOPT_POSTFIELDSIZE, -1);
|
||||||
|
curl_easy_setopt(i->curl, CURLOPT_HTTPHEADER, i->headers);
|
||||||
|
|
||||||
|
/* Create entity */
|
||||||
|
char *post = ngsi_update_context(n, "APPEND");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ngsi_close(struct node *n)
|
||||||
|
{
|
||||||
|
struct ngsi *i = n->ngsi;
|
||||||
|
|
||||||
|
curl_easy_cleanup(i->curl);
|
||||||
|
curl_slist_free_all(i->headers);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ngsi_query_context(struct node *n)
|
||||||
|
{
|
||||||
|
struct ngsi *i = n->ngsi;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char * ngsi_update_context(struct node *n, char *action)
|
||||||
|
{
|
||||||
|
struct ngsi *i = n->ngsi;
|
||||||
|
|
||||||
|
json_t *root = json_object();
|
||||||
|
json_t *elements = json_array();
|
||||||
|
|
||||||
|
for (int i = 0; i < i->entities; i++) {
|
||||||
|
json_t *entity = json_object();
|
||||||
|
json_t *attributes = json_object();
|
||||||
|
|
||||||
|
json_object_set(entity, "type", json_string("Room"));
|
||||||
|
json_object_set(entity, "isPattern", json_false());
|
||||||
|
json_object_set(entity, "id", json_string("Room1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
json_object_set(root, "contextElements", conextElements);
|
||||||
|
json_object_set(root, "updateAction", json_string(action));
|
||||||
|
|
||||||
|
return json_dumps(root, JSON_COMPACT);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ngsi_read(struct node *n, struct msg *pool, int poolsize, int first, int cnt)
|
||||||
|
{
|
||||||
|
struct ngsi *i = n->ngsi;
|
||||||
|
|
||||||
|
return -1; /** @todo not yet implemented */
|
||||||
|
}
|
||||||
|
|
||||||
|
int ngsi_write(struct node *n, struct msg *pool, int poolsize, int first, int cnt)
|
||||||
|
{
|
||||||
|
struct ngsi *i = n->ngsi;
|
||||||
|
|
||||||
|
long result;
|
||||||
|
char *post = ngsi_update_context(n, "UPDATE");
|
||||||
|
|
||||||
|
curl_easy_setopt(i->curl, CURLOPT_COPYPOSTFIELDS, post);
|
||||||
|
|
||||||
|
curl_easy_perform(i->curl);
|
||||||
|
|
||||||
|
curl_easy_getinfo(i->curl, CURLINFO_RESPONSE_CODE, &result);
|
||||||
|
|
||||||
|
return result == 200 ? 1 : 0
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_NODE_TYPE(NGSI, "ngsi", ngsi)
|
|
@ -108,6 +108,11 @@ struct node * node_create()
|
||||||
void node_destroy(struct node *n)
|
void node_destroy(struct node *n)
|
||||||
{
|
{
|
||||||
switch (n->vt->type) {
|
switch (n->vt->type) {
|
||||||
|
#ifdef ENABLE_NGSI
|
||||||
|
case NGSI:
|
||||||
|
list_destroy(n->ngsi->entities);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
#ifdef ENABLE_SOCKET
|
#ifdef ENABLE_SOCKET
|
||||||
case BSD_SOCKET:
|
case BSD_SOCKET:
|
||||||
rtnl_qdisc_put(n->socket->tc_qdisc);
|
rtnl_qdisc_put(n->socket->tc_qdisc);
|
||||||
|
|
Loading…
Add table
Reference in a new issue