Skip to main content

Південні Плагіни на C

Південні Плагіни, написані на C/C++, нічим не відрізняються у використанні від тих, що написані на Python, просто вони реалізовані на іншій мові. Існують ті ж варіанти опитуваних або асинхронних методів, і кінцевий користувач Fledge не знає, якою мовою написаний плагін.

Режим опитування

Режим опитування - це найпростіша форма південного плагіна, яку можна написати, процедура опитування викликається з інтервалом, визначеним у розширеній конфігурації плагіна. Південний сервіс визначає тип плагіна, досліджуючи властивість mode в інформації, яку плагін повертає після виклику plugin_info.

Опитування плагінів

Метод плагіна poll викликається періодично для збору показань з датчика в режимі опитування. Як і для всіх інших викликів, аргументом, що передається методу, є хендл, який повертається викликом plugin_init, а результатом методу має бути екземпляр Reading, який містить зчитані дані.

Клас Reading складається з

ВластивістьОпис
assetNameКлюч активу сенсорного пристрою, який зчитується
userTimestampПозначка часу для даних зчитування
datapointsСамі дані зчитування як набір екземплярів точки даних

Більш детально про клас Reading можна прочитати у розділі .

Важливо, щоб метод poll не блокувався, оскільки це перешкоджатиме належній роботі мікросервісу South. На прикладі нашого простого пристрою DHT11, підключеного до виводу GPIO, процедура poll може бути такою:

/**
* Poll for a plugin reading
*/
Reading plugin_poll(PLUGIN_HANDLE *handle)
{
DHT11 *dht11 = (DHT11*)handle;
return dht11->takeReading();
}

Де наш клас DHT11 має метод takeReading наступним чином

/**
* Take reading from sensor
*
* @param firstReading This flag indicates whether this is the first reading to be taken from sensor,
* if so get it reliably even if takes multiple retries. Subsequently (firstReading=false),
* if reading from sensor fails, last good reading is returned.
*/
Reading DHT11::takeReading(bool firstReading)
{
static uint8_t sensorData[4] = {0,0,0,0};

bool valid = false;
unsigned int count=0;
do {
valid = readSensorData(sensorData);
count++;
} while(!valid && firstReading && count < MAX_SENSOR_READ_RETRIES);

if (firstReading && count >= MAX_SENSOR_READ_RETRIES)
Logger::getLogger()->error("Unable to get initial valid reading from DHT11 sensor connected to pin %d even after %d tries", m_pin, MAX_SENSOR_READ_RETRIES);

vector<Datapoint *> vec;

ostringstream tmp;
tmp << ((unsigned int)sensorData[0]) << "." << ((unsigned int)sensorData[1]);
DatapointValue dpv1(stod(tmp.str()));
vec.push_back(new Datapoint("Humidity", dpv1));

ostringstream tmp2;
tmp2 << ((unsigned int)sensorData[2]) << "." << ((unsigned int)sensorData[3]);
DatapointValue dpv2(stod(tmp2.str()));
vec.push_back(new Datapoint ("Temperature", dpv2));

return Reading(m_assetName, vec);
}

Ми створюємо два DatapointValues для значень вологості та температури, які повертаються при зчитуванні датчика DHT11.

Опитування плагіна, що повертає кілька значень

У плагіні C/C++ можна створити плагін, який повертає декілька значень за один виклик процедури опитування. Для цього потрібно встановити версію інтерфейсу 2.0.0 замість 1.0.0. У цій версії інтерфейсу виклик plugin_poll повертає вектор Reading, а не одне Reading.

/**
* Poll for a plugin reading
*/
std::vector<Reading *> *plugin_poll(PLUGIN_HANDLE *handle)
{
Modbus *modbus = (Modbus *)handle;

if (!handle)
throw runtime_error("Bad plugin handle");
return modbus->takeReading();
}

Режим асинхронного введення-виведення

В асинхронному режимі плагін запускається або окремим потоком, або використовує вхідну подію від пристрою чи механізму зворотного виклику для запуску надсилання даних до Fledge. Асинхронний режим використовує дві додаткові точки входу до плагіна, одну для реєстрації зворотного виклику, за яким плагін надсилає дані, plugin_register_ingest, а іншу для запуску асинхронної поведінки plugin_start.

Plugin Register Ingest

Виклик plugin_register_ingest використовується для того, щоб дозволити південному сервісу передати плагіну функцію зворотного виклику, яку плагін використовує для надсилання даних до сервісу щоразу, коли у плагіна з'являються нові дані.

/**
* Register ingest callback
*/
void plugin_register_ingest(PLUGIN_HANDLE *handle, INGEST_CB cb, void *data)
{
MyPluginClass *plugin = (MyPluginClass *)handle;

if (!handle)
throw new exception();
plugin->registerIngest(data, cb);
}

Плагін повинен зберігати вказівник функції зворотного виклику і дані, пов'язані з цим викликом, так, щоб він міг використовувати цю інформацію для передачі показань до південного сервісу. Наступні фрагменти коду показують, як клас плагіна може зберігати функцію зворотного виклику і дані, а потім використовувати їх для надсилання показань до Fledge на більш пізньому етапі.

/**
* Record the ingest callback function and data in member variables
*
* @param data The Ingest function data
* @param cb The callback function to call
*/
void MyPluginClass::registerIngest(void *data, INGEST_CB cb)
{
m_ingest = cb;
m_data = data;
}

/**
* Called when a data is available to send to the south service
*
* @param points The points in the reading we must create
*/
void MyPluginClass::ingest(Reading& reading)
{

(*m_ingest)(m_data, reading);
}

Запуск Плагіна

Метод plugin_start, як і інші виклики плагіна, викликається з даними дескриптора плагіна, які було повернуто з виклику plugin_init. Виклик plugin_start буде викликано лише один раз для плагіна, і саме plugin_start відповідає за виконання будь-яких дій, необхідних у плагіні для запуску асинхронних дій плагіна. Це може бути запуск потоку, реєстрація кінцевої точки для віддаленого з'єднання або виклик точки входу у сторонній бібліотеці для початку асинхронної обробки.

/**     
* Start the Async handling for the plugin
*/
void plugin_start(PLUGIN_HANDLE *handle)
{
MyPluginClass *plugin = (MyPluginClass *)handle;


if (!handle)
return;
plugin->start();
}

/**
* Start the asynchronous processing thread
*/
void MyPluginClass::start()
{
m_running = true;
m_thread = new thread(threadWrapper, this);
}