From d1305a02504c488c8c8829275b96700b8790660b Mon Sep 17 00:00:00 2001 From: David Kebler Date: Sun, 8 Sep 2019 20:34:11 -0700 Subject: [PATCH] 0.1.14 go back to using super.read improve examples including home assistant coordination --- examples/homeassistant.js | 26 +++++++++---------- examples/{multi.js => relays.js} | 18 +++++++++++--- examples/{client.js => tcp-client.js} | 0 package.json | 20 +++++++-------- src/commands.js | 36 ++++++++++++++++++--------- src/gpio.js | 12 ++++++--- src/gpios.js | 14 +++++------ test/gpio.test.js | 4 ++- 8 files changed, 79 insertions(+), 51 deletions(-) rename examples/{multi.js => relays.js} (54%) rename examples/{client.js => tcp-client.js} (100%) diff --git a/examples/homeassistant.js b/examples/homeassistant.js index dd49634..2b72c7f 100644 --- a/examples/homeassistant.js +++ b/examples/homeassistant.js @@ -5,25 +5,25 @@ // uses main broker socket but formats incoming and outgoing packets for HA convention // TODO Make sure subscribed topics includes 'lighting/set/#' -const TOPIC = 'relays' +const TOPIC = 'relay' function register(name) { this.beforeProcessHook(async (packet) => { - console.log('incoming mqtt packet to modify') - console.dir(packet) + // console.log('incoming mqtt packet to modify') + // console.dir(packet) let cmd = packet.cmd.split('/') packet.cmd = `${packet.data.toLowerCase()}` packet.pins = cmd[2] delete packet.data - console.log('translated to uci packet') - console.dir(packet) + // console.log('translated to uci packet') + // console.dir(packet) return packet }, {name:name}) this.afterProcessHook(async (packet) => { - console.log('processed packet available to modify again', packet) + // console.log('processed packet available to modify again', packet) if (packet.error) { let npacket = {} npacket.cmd = 'error' @@ -36,14 +36,14 @@ function register(name) { {name:name}) this.beforeSendHook(async (packet) => { - console.log('beforeSendHook', packet) + // console.log('beforeSendHook', packet) if (packet.cmd === 'status') { - let num = Object.keys(packet.pins)[0] - packet.cmd = `${TOPIC}/status/${num}` - packet.payload = packet.pins[num] ? 'on' : 'off' - console.log('=============modified packet sent to broker================') - console.dir(packet) - console.log('================') + let pin = packet.pins || packet.pin || packet.gpios || packet.gpio || packet.ids || packet.id + packet.cmd = `${TOPIC}/status/${pin}` + packet.payload = (packet.state[pin]!=null ? packet.state[pin] : packet.state ) ? 'on' : 'off' + // console.log('=============modified packet sent to broker================') + // console.dir(packet) + // console.log('================') } return packet }, diff --git a/examples/multi.js b/examples/relays.js similarity index 54% rename from examples/multi.js rename to examples/relays.js index 5c1e162..c4a62f3 100644 --- a/examples/multi.js +++ b/examples/relays.js @@ -1,21 +1,31 @@ import Gpios from '../src/gpios' import hahooks from './homeassistant.js' -const PINS = [80,73,69,230,229,361,75,74,70] +const PINS = [80,73,69,230,229,75,74,70] +const ALL_PIN_OPTS = {activeLow:true, init:1} -let relays = new Gpios(PINS, {pinOpts:{activeLow:true}}) +let relays = new Gpios(PINS, {pinOpts:ALL_PIN_OPTS,69:{init:0}}) + +relays.announce = function () { + for (let pin of Object.keys(relays.pins)) { + relays.push({cmd:'status', pin:pin, state:relays.pins[pin].value}) + } +} const BROKER = 'nas.kebler.net' const TCP_PORT = 9075 +const WS_PORT = 8090 ; (async () => { - await relays.addSocket('mqs','s','m', {host:BROKER, topics:['relays/set/+']}) + await relays.addSocket('web','s','w',{ wsport:WS_PORT }) + await relays.addSocket('mqs','s','m', {host:BROKER, topics:['relay/set/+']}) hahooks.call(relays,'mqs') await relays.addSocket('tcp','s','t', {port:TCP_PORT}) - await relays.addSocket('web','s','w') await relays.init() + relays.announce() + // await relays.getSocket('mqs').subscribe(['relays/#']) })().catch(err => { diff --git a/examples/client.js b/examples/tcp-client.js similarity index 100% rename from examples/client.js rename to examples/tcp-client.js diff --git a/package.json b/package.json index dc4a5ae..8e71974 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { "name": "@uci/gpio", "main": "src", - "version": "0.1.13", + "version": "0.1.14", "description": "a class for adding simple on/off read of GPIO pins on SBCs including Raspberry Pi", "scripts": { - "client": "node -r esm examples/client", - "multi": "node --require esm examples/multi", - "multilog": "UCI_ENV=dev node --require esm examples/multi" + "client:tcp": "node -r esm examples/tcp-client", + "relays": "node --r esm examples/relays", + "relays:dev": "UCI_ENV=dev ./node_modules/.bin/nodemon -r esm examples/relays" }, "author": "David Kebler", "license": "MIT", @@ -26,16 +26,16 @@ }, "homepage": "https://github.com/uCOMmandIt/uci-interrrupt#readme", "dependencies": { - "@uci-utils/logger": "0.0.14", - "@uci/base": "^0.1.23", + "@uci-utils/logger": "^0.0.15", + "@uci/base": "^0.1.27", "death": "^1.1.0", - "onoff": "^4.1.1", + "onoff": "^4.1.4", "p-settle": "^3.1.0" }, "devDependencies": { - "chai": "^4.1.2", + "chai": "^4.2.0", "esm": "^3.2.25", - "mocha": "^5.0.1", - "nodemon": "^1.14.3" + "mocha": "^6.2.0", + "nodemon": "^1.19.2" } } diff --git a/src/commands.js b/src/commands.js index b88ee75..9e05d7f 100644 --- a/src/commands.js +++ b/src/commands.js @@ -5,7 +5,7 @@ let log = logger({package:'@uci/gpio', file:'/src/commands.js'}) export default { on: async function(packet) { packet.pinCmd = 'on' - this.commands.set(packet) + await this.commands.set(packet) return packet }, off: async function(packet) { @@ -20,28 +20,40 @@ export default { }, set: async function(packet) { packet.pinCmd = packet.pinCmd || 'set' - let pins = parsePins.call(this, packet.pins || packet.pin) - packet.res = await pSettle( - pins.map(pin => { - return this.pins[pin][packet.pinCmd](packet.value) - }) - ) - packet = await this.commands.get(packet) + log.debug({msg:'packet set request', packet:packet}) + let pins = parsePins.call(this, packet.pins || packet.pin || packet.gpios || packet.gpio || packet.ids || packet.id ) + log.debug({msg:'pins to set', packet:packet, pins:pins}) + // TODO could use this but need a way to know which res item is for what pin + // packet.res = await pSettle( + // pins.map(async pin => { + // return this.pins[pin][packet.pinCmd](packet.value) + // }), {concurrency:1} + // ) + packet.state = {} + for (let pin of pins) { + packet.state[pin] = await this.pins[pin][packet.pinCmd](packet.value) + } + log.info({msg:'pin(s) set result', packet:packet}) + packet.cmd='status' this.emit('gpios',packet) // emit locally this.push(packet) // will push on any socket return packet }, get: async function(packet) { - let pins = parsePins.call(this,packet.pins || packet.pin) - packet.pins = {} - pins.forEach(pin => packet.pins[pin] = this.pins[pin].value) + let pins = parsePins.call(this, this, packet.pins || packet.pin || packet.gpios || packet.gpio || packet.ids || packet.id) + packet.state = {} + pins.forEach(pin => packet.state[pin] = this.pins[pin].get(packet.read)) packet.cmd = 'status' return packet } } const parsePins = function(pins) { + if (!pins) { + console.log('no pins supplied aborting') + throw new Error('no pins specified in command') + } if (typeof pins==='number') pins = [pins] if (typeof pins==='string') { if (pins==='all') pins = Object.keys(this.pins) @@ -49,6 +61,6 @@ const parsePins = function(pins) { pins = pins.split(/[,:\s]+/).map(Number).filter( (x) => !Number.isNaN(x)) } } - // TODO plain object is pin and value pairs + if (pins.some(pin => !(pin in this.pins),this)) console.log('pin not available') return pins } diff --git a/src/gpio.js b/src/gpio.js index cdbfdb6..d138387 100644 --- a/src/gpio.js +++ b/src/gpio.js @@ -22,7 +22,7 @@ class Pin extends Gpio { } // end constructor async init() { - this.set(this.value) + await this.set(this.value) DeadJim((signal,err) => { log.warn({signal:signal, method:'init', line:56, error:err, msg:'gpio process was killed, unexporting pin'}) this.unexport() // kill the kernel entry @@ -34,6 +34,8 @@ class Pin extends Gpio { async toggle() { return await this.set(!this.value) } async set(value) { + log.debug({msg:'set a pin', value:value, number:this.number}) + // this.write(parseInt(value) || 0).then(res => console.log('returning from write')) let [err] = await to(this.write(parseInt(value) || 0)) if (err) { log.warn({error:err, pin:this.number, msg:'error reading gpio pin'}) @@ -45,17 +47,19 @@ class Pin extends Gpio { } async read() { - let [err, res] = await to(super.read()) + let [err, res] = await to(super.read()) // super.read here just calls this.read making an infinite loop and blowing the stack, should call onoff's read if (err) { log.warn({error:err, pin:this.pin, msg:'error reading gpio pin'}) return err } this.value=res this.state = res ? 'on' : 'off' - return res + return this.value } - async get() { return this.value } + async get() { + return this.value + } } // end Class diff --git a/src/gpios.js b/src/gpios.js index 3cb9cb0..1561620 100644 --- a/src/gpios.js +++ b/src/gpios.js @@ -19,7 +19,7 @@ class Gpios extends Base { log = logger({ name: 'gpios', id: this.id, package:'@uci/gpios', file:'src/gpios.js'}) pins.forEach(pin => { if (typeof pin !=='number') pin = parseInt(pin) - opts[pin] = opts[pin] ? opts[pin] : opts.pinOpts + opts[pin] = Object.assign({},opts.pinOpts || {}, opts[pin] || {}) log.debug({ opts: opts[pin], line:27, msg:`pin options for pin ${pin}`}) this.pins[pin] = new Gpio(pin, opts[pin]) }) @@ -28,15 +28,15 @@ class Gpios extends Base { } async init() { + console.log('init') + for (let pin of Object.keys(this.pins)) { + log.debug({msg:`initializing pin ${pin} with ${this.pins[pin].value}`}) + await this.pins[pin].init() + } await super.init() - return Promise.all( - Object.keys(this.pins).map(pin => { - return this.pins[pin].init() - }) - ) + return 'ready' } - // register same hook to all pins registerHook(func) { this.pins.forEach(async pin => { diff --git a/test/gpio.test.js b/test/gpio.test.js index a8ed8c7..dd6f99d 100644 --- a/test/gpio.test.js +++ b/test/gpio.test.js @@ -1,7 +1,9 @@ 'use strict' +// just a starting template + const - Gpio = require('../src/interrupt'), + Gpio = require('../src/gpios'), expect = require('chai').expect // TODO finish simple test of a pin as interrupt