irrigation/src/ha-mqtt.js

102 lines
3.4 KiB
JavaScript

///***************** HOME ASSISTANT ************************
// for uci mqtt discovery in HA
const STATE_TOPIC = 'state'
const STATE_CMD = 'state'
const ENTITY = 'switch'
const DISCOVERY = 'homeassistant'
const NAMESPACE = 'uci'
const COMMAND_TOPIC = 'set' // will use payload as the command
function register(name,opts={}) {
const topic = `${opts.discovery || DISCOVERY}/` +
`${opts.entity || ENTITY}/` +
`${opts.namespace || NAMESPACE ? `${opts.namespace || NAMESPACE }` :''}`
console.log('subscription topic for HA',`${topic}/#`)
this.getSocket(name).subscribe(`${topic}/#`)
this.beforeProcessHook(async (packet) => {
// console.log('incoming ha mqtt packet to modify')
// console.dir(packet)
// let modified = Object.assign({},packet)
const topic = packet.cmd.split('/')
const cmd = topic.pop()
const id = topic.pop()
// console.log(cmd, id)
if (cmd=== (opts.state || STATE_TOPIC)) return null // ignore state commands (avoid infiite loop)
else if (cmd===(opts.command||COMMAND_TOPIC)) packet.cmd = packet.data.toLowerCase()
else packet.cmd = cmd
delete packet.data
Object.assign(packet,this.entities.find(ent => ent.id === id))
// console.log('translated to uci packet')
// console.dir(packet)
return packet
},
{name:name})
this.afterProcessHook(async (packet) => {
if (packet.error) {
let npacket = {}
npacket.cmd = 'error'
npacket.payload = JSON.stringify(packet)
return npacket
}
// console.log('after process', packet)
return packet
},
{name:name})
this.beforeSendHook(async (packet) => {
if (packet.cmd === (opts.stateCmd || STATE_CMD)) {
// console.log('preparing state topic/payload')
if (packet.state && packet.gpio) {
let mpacket = {
cmd: `${topic}/${packet.id}/${opts.stateCmd || STATE_CMD}`,
payload: ((packet.state || {})[packet.gpio.toString()] || '').toUpperCase()
}
// console.log('=============modified packet being pushed to broker================')
// console.dir(mpacket)
// console.log('================')
return mpacket
}
// else console.log('bad state packet state/gpio',packet.state,packet.gpio)
}
// console.log('packet ignored, nothing sent to to HA')
return null // only send/publish the required topic
},
{name:name})
}
export default register
function init(mqtt,entities,opts={}) {
console.log('initializing ha mqtt discovery')
entities.forEach(ent => {
const topic = `${opts.discovery || DISCOVERY}/` +
`${opts.entity || ENTITY}/` +
`${opts.namespace || NAMESPACE ? `${opts.namespace || NAMESPACE }/` :''}` +
`${ent.id}`
let payload = {
name:`${opts.namespace || NAMESPACE ? `${opts.namespace || NAMESPACE }_` :''}${ent.id}`,
command_topic:`${topic}/${opts.command || COMMAND_TOPIC}`,
state_topic: `${topic}/${opts.state || STATE_TOPIC}`,
json_attributes_topic:`${topic}/${opts.state || STATE_TOPIC}`,
json_attributes_template:'{{ value_json.alias | tojson }}',
}
payload = JSON.stringify(payload)
console.log('------ sending discovery payload to HA for ',ent.alias,':',ent.id,'-----')
console.log('topic=>',`${topic}/config`)
// console.log(payload)
mqtt.publish(`${topic}/info`,null) // clear existing
mqtt.publish(`${topic}/config`,payload,{retain:true})
})
}
export { register,init }