О сниппетах
Сниппеты — это небольшие фрагменты кода, пригодные для повторного использования.
В системе 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"); // Данные получены, но парсинг неудачен } }); }); };