0.1.14 go back to using super.read

improve examples including home assistant coordination
master
David Kebler 2019-09-08 20:34:11 -07:00
parent 779f762cc4
commit d1305a0250
8 changed files with 79 additions and 51 deletions

View File

@ -5,25 +5,25 @@
// uses main broker socket but formats incoming and outgoing packets for HA convention // uses main broker socket but formats incoming and outgoing packets for HA convention
// TODO Make sure subscribed topics includes 'lighting/set/#' // TODO Make sure subscribed topics includes 'lighting/set/#'
const TOPIC = 'relays' const TOPIC = 'relay'
function register(name) { function register(name) {
this.beforeProcessHook(async (packet) => { this.beforeProcessHook(async (packet) => {
console.log('incoming mqtt packet to modify') // console.log('incoming mqtt packet to modify')
console.dir(packet) // console.dir(packet)
let cmd = packet.cmd.split('/') let cmd = packet.cmd.split('/')
packet.cmd = `${packet.data.toLowerCase()}` packet.cmd = `${packet.data.toLowerCase()}`
packet.pins = cmd[2] packet.pins = cmd[2]
delete packet.data delete packet.data
console.log('translated to uci packet') // console.log('translated to uci packet')
console.dir(packet) // console.dir(packet)
return packet return packet
}, },
{name:name}) {name:name})
this.afterProcessHook(async (packet) => { 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) { if (packet.error) {
let npacket = {} let npacket = {}
npacket.cmd = 'error' npacket.cmd = 'error'
@ -36,14 +36,14 @@ function register(name) {
{name:name}) {name:name})
this.beforeSendHook(async (packet) => { this.beforeSendHook(async (packet) => {
console.log('beforeSendHook', packet) // console.log('beforeSendHook', packet)
if (packet.cmd === 'status') { if (packet.cmd === 'status') {
let num = Object.keys(packet.pins)[0] let pin = packet.pins || packet.pin || packet.gpios || packet.gpio || packet.ids || packet.id
packet.cmd = `${TOPIC}/status/${num}` packet.cmd = `${TOPIC}/status/${pin}`
packet.payload = packet.pins[num] ? 'on' : 'off' packet.payload = (packet.state[pin]!=null ? packet.state[pin] : packet.state ) ? 'on' : 'off'
console.log('=============modified packet sent to broker================') // console.log('=============modified packet sent to broker================')
console.dir(packet) // console.dir(packet)
console.log('================') // console.log('================')
} }
return packet return packet
}, },

View File

@ -1,21 +1,31 @@
import Gpios from '../src/gpios' import Gpios from '../src/gpios'
import hahooks from './homeassistant.js' 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 BROKER = 'nas.kebler.net'
const TCP_PORT = 9075 const TCP_PORT = 9075
const WS_PORT = 8090
; ;
(async () => { (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') hahooks.call(relays,'mqs')
await relays.addSocket('tcp','s','t', {port:TCP_PORT}) await relays.addSocket('tcp','s','t', {port:TCP_PORT})
await relays.addSocket('web','s','w')
await relays.init() await relays.init()
relays.announce()
// await relays.getSocket('mqs').subscribe(['relays/#']) // await relays.getSocket('mqs').subscribe(['relays/#'])
})().catch(err => { })().catch(err => {

View File

@ -1,12 +1,12 @@
{ {
"name": "@uci/gpio", "name": "@uci/gpio",
"main": "src", "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", "description": "a class for adding simple on/off read of GPIO pins on SBCs including Raspberry Pi",
"scripts": { "scripts": {
"client": "node -r esm examples/client", "client:tcp": "node -r esm examples/tcp-client",
"multi": "node --require esm examples/multi", "relays": "node --r esm examples/relays",
"multilog": "UCI_ENV=dev node --require esm examples/multi" "relays:dev": "UCI_ENV=dev ./node_modules/.bin/nodemon -r esm examples/relays"
}, },
"author": "David Kebler", "author": "David Kebler",
"license": "MIT", "license": "MIT",
@ -26,16 +26,16 @@
}, },
"homepage": "https://github.com/uCOMmandIt/uci-interrrupt#readme", "homepage": "https://github.com/uCOMmandIt/uci-interrrupt#readme",
"dependencies": { "dependencies": {
"@uci-utils/logger": "0.0.14", "@uci-utils/logger": "^0.0.15",
"@uci/base": "^0.1.23", "@uci/base": "^0.1.27",
"death": "^1.1.0", "death": "^1.1.0",
"onoff": "^4.1.1", "onoff": "^4.1.4",
"p-settle": "^3.1.0" "p-settle": "^3.1.0"
}, },
"devDependencies": { "devDependencies": {
"chai": "^4.1.2", "chai": "^4.2.0",
"esm": "^3.2.25", "esm": "^3.2.25",
"mocha": "^5.0.1", "mocha": "^6.2.0",
"nodemon": "^1.14.3" "nodemon": "^1.19.2"
} }
} }

View File

@ -5,7 +5,7 @@ let log = logger({package:'@uci/gpio', file:'/src/commands.js'})
export default { export default {
on: async function(packet) { on: async function(packet) {
packet.pinCmd = 'on' packet.pinCmd = 'on'
this.commands.set(packet) await this.commands.set(packet)
return packet return packet
}, },
off: async function(packet) { off: async function(packet) {
@ -20,28 +20,40 @@ export default {
}, },
set: async function(packet) { set: async function(packet) {
packet.pinCmd = packet.pinCmd || 'set' packet.pinCmd = packet.pinCmd || 'set'
let pins = parsePins.call(this, packet.pins || packet.pin) log.debug({msg:'packet set request', packet:packet})
packet.res = await pSettle( let pins = parsePins.call(this, packet.pins || packet.pin || packet.gpios || packet.gpio || packet.ids || packet.id )
pins.map(pin => { log.debug({msg:'pins to set', packet:packet, pins:pins})
return this.pins[pin][packet.pinCmd](packet.value) // 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 => {
packet = await this.commands.get(packet) // 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.emit('gpios',packet) // emit locally
this.push(packet) // will push on any socket this.push(packet) // will push on any socket
return packet return packet
}, },
get: async function(packet) { get: async function(packet) {
let pins = parsePins.call(this,packet.pins || packet.pin) let pins = parsePins.call(this, this, packet.pins || packet.pin || packet.gpios || packet.gpio || packet.ids || packet.id)
packet.pins = {} packet.state = {}
pins.forEach(pin => packet.pins[pin] = this.pins[pin].value) pins.forEach(pin => packet.state[pin] = this.pins[pin].get(packet.read))
packet.cmd = 'status' packet.cmd = 'status'
return packet return packet
} }
} }
const parsePins = function(pins) { 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==='number') pins = [pins]
if (typeof pins==='string') { if (typeof pins==='string') {
if (pins==='all') pins = Object.keys(this.pins) 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)) 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 return pins
} }

View File

@ -22,7 +22,7 @@ class Pin extends Gpio {
} // end constructor } // end constructor
async init() { async init() {
this.set(this.value) await this.set(this.value)
DeadJim((signal,err) => { DeadJim((signal,err) => {
log.warn({signal:signal, method:'init', line:56, error:err, msg:'gpio process was killed, unexporting pin'}) log.warn({signal:signal, method:'init', line:56, error:err, msg:'gpio process was killed, unexporting pin'})
this.unexport() // kill the kernel entry this.unexport() // kill the kernel entry
@ -34,6 +34,8 @@ class Pin extends Gpio {
async toggle() { return await this.set(!this.value) } async toggle() { return await this.set(!this.value) }
async set(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)) let [err] = await to(this.write(parseInt(value) || 0))
if (err) { if (err) {
log.warn({error:err, pin:this.number, msg:'error reading gpio pin'}) log.warn({error:err, pin:this.number, msg:'error reading gpio pin'})
@ -45,17 +47,19 @@ class Pin extends Gpio {
} }
async read() { 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) { if (err) {
log.warn({error:err, pin:this.pin, msg:'error reading gpio pin'}) log.warn({error:err, pin:this.pin, msg:'error reading gpio pin'})
return err return err
} }
this.value=res this.value=res
this.state = res ? 'on' : 'off' this.state = res ? 'on' : 'off'
return res return this.value
} }
async get() { return this.value } async get() {
return this.value
}
} // end Class } // end Class

View File

@ -19,7 +19,7 @@ class Gpios extends Base {
log = logger({ name: 'gpios', id: this.id, package:'@uci/gpios', file:'src/gpios.js'}) log = logger({ name: 'gpios', id: this.id, package:'@uci/gpios', file:'src/gpios.js'})
pins.forEach(pin => { pins.forEach(pin => {
if (typeof pin !=='number') pin = parseInt(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}`}) log.debug({ opts: opts[pin], line:27, msg:`pin options for pin ${pin}`})
this.pins[pin] = new Gpio(pin, opts[pin]) this.pins[pin] = new Gpio(pin, opts[pin])
}) })
@ -28,15 +28,15 @@ class Gpios extends Base {
} }
async init() { 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() await super.init()
return Promise.all( return 'ready'
Object.keys(this.pins).map(pin => {
return this.pins[pin].init()
})
)
} }
// register same hook to all pins // register same hook to all pins
registerHook(func) { registerHook(func) {
this.pins.forEach(async pin => { this.pins.forEach(async pin => {

View File

@ -1,7 +1,9 @@
'use strict' 'use strict'
// just a starting template
const const
Gpio = require('../src/interrupt'), Gpio = require('../src/gpios'),
expect = require('chai').expect expect = require('chai').expect
// TODO finish simple test of a pin as interrupt // TODO finish simple test of a pin as interrupt