О сниппетах
Сниппеты — это небольшие фрагменты кода, пригодные для повторного использования.
В системе intraHouse можно использовать сниппеты для получения значений устройств без привязки к каналам плагинов. То есть это легковесная замена плагина.
Данные можно получить, используя http-запрос, или запуская команду терминала, или считывая файл.
Например, в ОС Linux многие значения можно получить, просто читая файл.
Пример 1. Сниппет для чтения температуры CPU из файла /sys/class/thermal/thermal_zone0/temp
/**
* New snippet
*/
const fs = require('fs');
module.exports = callback => {
fs.readFile('/sys/class/thermal/thermal_zone0/temp', 'utf8', (err, data) => {
if (err) {
callback(err.code);
} else if (isNaN(data)) {
callback('Result '+data+' is not a number!');
} else {
callback(null, Math.round(Number(data) / 1000));
}
});
};
Примечание: Деление на 1000 выполняется, так как из файла читается целое число в тысячных градуса.
Часто данные можно получить, запуская терминальную команду.
Пример 2. Сниппет для получения температуры на RPI с использованием команды vcgencmd
/**
* New snippet
*/
module.exports = callback => {
require('child_process').exec('vcgencmd measure_temp', (error, stdout) => {
let value;
if (!error && stdout && stdout.substr(0, 4) == 'temp') {
value = parseFloat(stdout.split('=').pop());
}
callback( error || value === undefined, value);
});
};
Использование сниппетов
Сниппет создается прямо в таблице устройств.
На вкладке «Дополнительно» добавлен чекбокс: Для получения значений использовать сниппет
Внимание! Сниппет можно использовать, если устройство не привязано к каналу плагина.
Если поставить галочку, будет открыто свойство Период запуска сниппета, а в нижнем окне будет доступен раздел Сниппет, который является редактором кода. Здесь надо добавить код сниппета.
Этот код будет вызываться циклически с заданным периодом.
Создание кода сниппета
Код создается в виде модуля, экспортирующего функцию. Аргумент callback — это функция обратного вызова, которая вернет результат в систему.
Никаких ограничений по структуре и синтаксису модуля нет. Предпочтительно использование асинхронных команд.
Ниже Пример 2, но с использованием старого синтаксиса JavaScipt. В первом варианте используются стрелочные функции нового синтаксиса ES6. Допустимы оба варианта.
/**
* New snippet
*/
module.exports = function(callback) {
require('child_process').exec('vcgencmd measure_temp', function (error, stdout) {
let value;
if (!error && stdout && stdout.substr(0, 4) == 'temp') {
value = parseFloat(stdout.split('=').pop());
}
callback( error || value === undefined, value);
});
};
Возврат значения
Как принято в Node.js, функция обратного вызова callback возвращает ошибку в первом аргументе.
То есть, чтобы передать значение value, нужно вызвать callback одним из этих способов:
callback(null, value);
callback(0, value);
callback('', value);
Возврат ошибки
Если в первом аргументе передать не пустое значение и не ноль, это будет означать ошибку, второй аргумент будет проигнорирован.
Можно вернуть текст ошибки, тогда он появится в журнале устройства с добавлением ‘Ошибка!’
Пример 3. Достаем температуру с погодного сайта Gismeteo
/**
* New snippet
*/
module.exports = callback => {
const regexp = /{"temperature":{"air":{"C":(.*?),"F"/gm;
require('https').get('https://www.gismeteo.ru/weather-moscow-4368/now/', res => {
if (res.statusCode != 200) {
res.resume();
callback("statusCode="+res.statusCode); // Сайт вернул статус ошибки, данные не получены
return;
}
let rawData = '';
res.on('data', chunk => {
rawData += chunk;
});
res.on('end', () => {
const arr = regexp.exec(rawData);
if (arr && arr.length>1) {
callback(null, arr[1]); // Данные получены, парсинг удачен
} else {
callback("Regexp вернул null"); // Данные получены, но парсинг неудачен
}
});
});
};