'use strict'; let Gpio = require('onoff').Gpio; //include onoff to interact with the GPIO let gpioMock = require('gpio-mock'); let DHTSensor = require("node-dht-sensor"); //GPIO Definitions let GPIO_PIN_25 = 25; // Motion Sensor let GPIO_PIN_16 = 16; // LED let GPIO_PIN_12 = 12; // Buzzer let GPIO_PIN_21 = 21; // Hygrothermograph Sensor let STATUS_OFF = 0; let STATUS_ON = 1; let HYGRO_THERMO_GRAPH_SENSOR_TYPE_DHT11 = 11; // Motion detection modes const MODE_ON_ONLY= 'MODE_ON_ONLY'; const MODE_OFF_ONLY = 'MODE_OFF_ONLY'; const MODE_BOTH = 'MODE_BOTH'; const SENSOR_QUERY_INTERVAL = 1000; // .1 sec // Presence detection time to switch to user search screen const DEFAULT_PRESENCE_ON_DELAY = 1000; // 1 second // Time to switch back to splash screen after no more presence const DEFAULT_PRESENCE_OFF_DELAY = 10000; // 10 seconds // Time before starting motion after initialization const DEFAULT_INITIAL_MOTION_DETECTION_DELAY = 0; // LED Flashing on and off default times const LED_FLASH_SPEED_DEFAULT_TIME = 500; // 500 ms let GpioHelper = function (logger, mock) { let motionSensor; let LED; let buzzer; let motionSensorTimer; let presenceNotificationDelayTimer; let currentDetectionStatus = null; let ledFlashingTimer; let motionSensorOptions; let self = this; if (mock) { logger.debug('[GPIO] It seems we are not running on an actual RPI. Mocking of GPIO shall start'); gpioMock.start(function () { logger.debug('[GPIO] GPIO Mocking Started'); }); } this.initMotionSensor = function(gpioPin) { motionSensor = new Gpio(gpioPin || GPIO_PIN_25, 'in', 'both'); }; this.initPresenceChangeSensor = function(options) { if (!options || !options.callback) { logger.error('[GPIO] Not enough options to initialize motion sensor'); return; } motionSensorOptions = options; motionSensor = new Gpio(motionSensorOptions.gpioPin || GPIO_PIN_25, 'in', 'both'); if(options.detection === STATUS_ON) { setTimeout(() => self.restartPresenceDetection(motionSensorOptions), options.initialDelay || DEFAULT_INITIAL_MOTION_DETECTION_DELAY); } }; this.restartPresenceDetection = function(options) { logger.debug('[GPIO] Restart Precense Detection'); options = options || motionSensorOptions; if (!options.callback) { logger.error('[GPIO] Not enough options to initialize motion sensor'); return; } if (motionSensorTimer) { clearInterval(motionSensorTimer); } motionSensorTimer = setInterval(() => { motionSensor.read((error, status) => { if (!error) { if (currentDetectionStatus === null || currentDetectionStatus !== status) { logger.debug(`[GPIO] Status change. Old status = ${currentDetectionStatus}. New status ${status}.`); if (presenceNotificationDelayTimer) { clearTimeout(presenceNotificationDelayTimer); } presenceNotificationDelayTimer = setTimeout(() => { logger.debug(`[GPIO] Invoke callback with status ${status}`); options.callback(status); }, status === STATUS_OFF ? motionSensorOptions.presenceOffDelay || DEFAULT_PRESENCE_OFF_DELAY : motionSensorOptions.presenceOnDelay || DEFAULT_PRESENCE_ON_DELAY); } currentDetectionStatus = status; return; } logger(`[GPIO] Error querying sensor: Error ${error}`); }); }, options.presenceCheckTime || SENSOR_QUERY_INTERVAL); }; this.stopPresenceDetection = function() { logger.debug('[GPIO] Stop Precense Detection'); if(motionSensorTimer) { clearInterval(motionSensorTimer); motionSensorTimer = null; } }; this.initLED = function(gpioPin, status) { LED = new Gpio(gpioPin || GPIO_PIN_16, 'out'); self.setLED(status); }; this.setLED = function(status) { if (ledFlashingTimer) { clearInterval(ledFlashingTimer); ledFlashingTimer = null; } LED.writeSync(status); }; this.flashLED = function(speed) { speed = speed || LED_FLASH_SPEED_DEFAULT_TIME; let status = STATUS_ON; LED.writeSync(status); if (ledFlashingTimer) { clearInterval(ledFlashingTimer); } ledFlashingTimer = setInterval(() => { status = status === STATUS_ON ? STATUS_OFF : STATUS_ON; LED.writeSync(status); }, speed); }; this.initBuzzer = function(gpioPin, status) { buzzer = new Gpio(gpioPin || GPIO_PIN_12, 'out'); self.setBuzzer(status); }; this.setBuzzer = function(status) { buzzer.writeSync(status); }; this.readTempAndHumidity = function (cb, gpioPin, dhtType) { cb = cb || {}; if (mock) { cb(25,45); return; } DHTSensor.read(dhtType || HYGRO_THERMO_GRAPH_SENSOR_TYPE_DHT11, gpioPin || GPIO_PIN_21, function(err, temp, humidity) { if(!err) { logger.debug(`Temperature: ${temp.toFixed(1)} °C. Humidity: ${humidity.toFixed(1)} %`); cb(temp, humidity); } else { logger.error(`Error reading DHT11. Error: ${err}`); } }); }; this.getCurrentMotionSensorStatus = function () { if (!motionSensor) { logger.error('[GPIO] Motion sensor has not be initialized yet'); return; } return motionSensor.readSync(); }; }; module.exports = GpioHelper; module.exports.MODE_BOTH = MODE_BOTH; module.exports.MODE_ON_ONLY = MODE_ON_ONLY; module.exports.MODE_OFF_ONLY = MODE_OFF_ONLY; module.exports.STATUS_OFF = STATUS_OFF; module.exports.STATUS_ON = STATUS_ON;