{"version":3,"sources":["jsdelivr-header.js","/npm/homekit2mqtt@1.1.2/index.js"],"names":[],"mappings":"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","file":"/npm/homekit2mqtt@1.1.2/index.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/homekit2mqtt@1.1.2/index.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","#!/usr/bin/env node\n\nconst fs = require('fs');\nconst path = require('path');\nconst crypto = require('crypto');\nconst Mqtt = require('mqtt');\nconst chalk = require('chalk');\nconst qrcode = require('qrcode-terminal');\nconst nextport = require('nextport');\nconst oe = require('obj-ease');\nconst express = require('express');\nconst bodyParser = require('body-parser');\nconst basicAuth = require('express-basic-auth');\n\nconst app = express();\n\nconst log = require('yalm');\nconst HAP = require('hap-nodejs');\nconst pkgHap = require('hap-nodejs/package.json');\nconst pkg = require('./package.json');\nconst config = require('./config.js');\n\nlog.setLevel(config.verbosity);\n\nlog(pkg.name + ' ' + pkg.version + ' starting');\nprocess.title = pkg.name;\n\nconst mqttStatusRaw = {}; // Holds the payloads of the last-received message, keys are the topics.\n\nfunction mqttStatus(topic, attr) { // Holds the payloads of the last-received message, keys are the topics.\n    if (attr && typeof mqttStatusRaw[topic] === 'object') {\n        return oe.getProp(mqttStatusRaw[topic], attr);\n    }\n    return mqttStatus[topic];\n}\n\nconst mqttCallbacks = {}; // Holds arrays of subscription callbacks, keys are the topics.\nlet mqttConnected;\n\nlet bridgeListening;\nconst topics = [];\n\nlog.info('mqtt trying to connect', config.url);\nconst mqtt = Mqtt.connect(config.url, {\n    will: {topic: config.name + '/connected', payload: '0', retain: true},\n    rejectUnauthorized: !config.insecure\n});\n\nmqtt.on('connect', () => {\n    mqttConnected = true;\n    log.info('mqtt connected ' + config.url);\n    /* istanbul ignore next */\n    if (!bridgeListening) {\n        mqttPub(config.name + '/connected', '1', {retain: true});\n    }\n});\n\n/* istanbul ignore next */\nmqtt.on('reconnect', () => {\n    log.info('mqtt reconnect');\n});\n\n/* istanbul ignore next */\nmqtt.on('offline', () => {\n    log.info('mqtt offline');\n});\n\n/* istanbul ignore next */\nmqtt.on('close', () => {\n    if (mqttConnected) {\n        mqttConnected = false;\n        log.info('mqtt closed ' + config.url);\n    }\n});\n\n/* istanbul ignore next */\nmqtt.on('error', err => {\n    log.error('mqtt error ' + err);\n});\n\nfunction typeGuess(payload) {\n    let state;\n    // Nasty type guessing.\n    // TODO clarify Do we really want/need to cast the strings \"true\" and \"false\" to bool? https://github.com/hobbyquaker/homekit2mqtt/issues/66\n    if (payload === 'true') {\n        state = true;\n    } else if (payload === 'false') {\n        state = false;\n    } else if (isNaN(payload)) {\n        state = payload;\n    } else {\n        state = parseFloat(payload);\n    }\n    return state;\n}\n\n// MQTT subscribe function that provides a callback on incoming messages.\n// Not meant to be used with wildcards!\nfunction mqttSub(topic, /* string, optional, default \"val\" */ attr, callback) {\n    topic = String(topic);\n    /* istanbul ignore next */\n    if (topic === '') {\n        log.error('trying to subscribe empty topic');\n        return;\n    }\n    /* istanbul ignore if */\n    if (typeof attr === 'function') {\n        callback = attr;\n        attr = 'val';\n    } else if (attr) {\n        attr = String(attr);\n    } else {\n        attr = 'val';\n    }\n    /* istanbul ignore else */\n    if (typeof callback === 'function') {\n        /* istanbul ignore if */\n        if (mqttCallbacks[topic]) {\n            mqttCallbacks[topic].push({attr, callback});\n        } else {\n            mqttCallbacks[topic] = [{attr, callback}];\n            log.debug('mqtt subscribe', topic);\n            mqtt.subscribe(topic);\n        }\n    } else {\n        log.debug('mqtt subscribe', topic);\n        mqtt.subscribe(topic);\n    }\n}\n\n// MQTT publish function, checks for valid topic and converts payload to string in a meaningful manner.\nfunction mqttPub(topic, payload, options) {\n    /* istanbul ignore if */\n    if (!topic || (typeof topic !== 'string')) {\n        log.error('mqttPub invalid topic', topic);\n    } else {\n        /* istanbul ignore if */\n        if (typeof payload === 'object') {\n            payload = JSON.stringify(payload);\n        /* istanbul ignore next */\n        } else if (typeof payload === 'undefined') {\n            payload = '';\n        } else if (typeof payload !== 'string') {\n            payload = String(payload);\n        }\n        log.debug('> mqtt', topic, payload);\n\n        /* istanbul ignore if */\n        if (config.retain) {\n            if (!options) {\n                options = {};\n            }\n            options.retain = true;\n        }\n        mqtt.publish(topic, payload, options, err => {\n            /* istanbul ignore next */\n            if (err) {\n                log.error('mqtt publish error ' + err);\n            }\n        });\n    }\n}\n\nlog.info('using hap-nodejs version', pkgHap.version);\n\nconst {uuid, Bridge, Accessory, Service, Characteristic} = HAP;\n\n/* istanbul ignore next */\nif (config.storagedir) {\n    log.info('using directory ' + config.storagedir + ' for persistent storage');\n}\n// If storagedir is not set it uses HAP-Nodejs default\n// (usually /usr/local/lib/node_modules/homekit2mqtt/node_modules/node-persist/persist)\nHAP.init(config.storagedir || undefined);\n\n// Create Bridge which will host all Accessories\nconst bridge = new Bridge(config.bridgename, uuid.generate(config.bridgename));\n\n// Listen for Bridge identification event\n/* istanbul ignore next */\nbridge.on('identify', (paired, callback) => {\n    log('< hap bridge identify', paired ? '(paired)' : '(unpaired)');\n    callback();\n});\n\n// Handler for Accessory identification events\n/* istanbul ignore next */\nfunction identify(settings, paired, callback) {\n    log.debug('< hap identify', settings.name, paired ? '(paired)' : '(unpaired)');\n    if (settings.topicIdentify) {\n        log.debug('> mqtt', settings.topicIdentify, settings.payloadIdentify);\n        mqttPub(settings.topicIdentify, settings.payloadIdentify);\n    }\n    callback();\n}\n\nfunction mac(data) {\n    const sha1sum = crypto.createHash('sha1');\n    sha1sum.update(data);\n    const s = sha1sum.digest('hex');\n    let i = -1;\n    return 'xx:xx:xx:xx:xx:xx'.replace(/[x]/g, () => {\n        i += 1;\n        return s[i];\n    }).toUpperCase();\n}\n\nfunction newAccessory(settings) {\n    log.debug('creating new accessory', '\"' + settings.name + '\"', '\"' + settings.id + '\"', uuid.generate(settings.id));\n    const acc = new Accessory(settings.name, uuid.generate(settings.id), settings.category);\n    if (settings.manufacturer || settings.model || settings.serial) {\n        acc.getService(Service.AccessoryInformation)\n            .setCharacteristic(Characteristic.Manufacturer, settings.manufacturer || '-')\n            .setCharacteristic(Characteristic.Model, settings.model || '-')\n            .setCharacteristic(Characteristic.SerialNumber, settings.serial || '-');\n    }\n    if (!settings.payload) {\n        settings.payload = {};\n    }\n    if (!settings.config) {\n        settings.config = {};\n    }\n    /* istanbul ignore next */\n    acc.on('identify', (paired, callback) => {\n        identify(settings, paired, callback);\n    });\n    return acc;\n}\n\nconst addService = {};\n\nfunction loadService(service) {\n    const file = 'services/' + service + '.js';\n    log.debug('loading', file);\n    addService[service] = require(path.join(__dirname, file))({mqttPub, mqttSub, mqttStatus, log, Service, Characteristic, HAP});\n}\n\nlet mapping;\nlet accCount;\n\n/* Convert old config file schema to keep compatiblity */\n/* istanbul ignore next */\nfunction convertMapping() {\n    let isConverted;\n    Object.keys(mapping).forEach(id => {\n        const accConfig = mapping[id];\n\n        if (!accConfig.services) {\n            accConfig.services = [];\n            isConverted = true;\n        }\n\n        if (accConfig.topic && accConfig.topic.identify) {\n            accConfig.topicIdentify = accConfig.topic.identify;\n            delete accConfig.topic.identify;\n            isConverted = true;\n        }\n\n        if (accConfig.payload && accConfig.payload.identify) {\n            accConfig.payloadIdentify = accConfig.payload.identify;\n            delete accConfig.payload.identify;\n            isConverted = true;\n        }\n\n        if (accConfig.service) {\n            accConfig.services.unshift({\n                name: accConfig.name,\n                service: accConfig.service,\n                topic: accConfig.topic || {},\n                payload: accConfig.payload || {},\n                config: accConfig.config || {},\n                props: accConfig.props || {}\n            });\n            delete accConfig.service;\n            delete accConfig.topic;\n            delete accConfig.payload;\n            delete accConfig.config;\n            delete accConfig.props;\n            isConverted = true;\n        }\n    });\n    if (isConverted) {\n        log.info('mapping file converted');\n        saveMapping();\n    }\n}\n\nfunction createBridge() {\n    mqtt.on('message', (topic, payload) => {\n        payload = payload.toString();\n        let json;\n        if (payload.indexOf('{') !== -1 && !config.disableJsonParse) {\n            try {\n                json = JSON.parse(payload);\n            } catch (err) {}\n        }\n        const state = typeGuess(payload);\n        log.debug('< mqtt', topic, state, payload);\n\n        mqttStatusRaw[topic] = json || state;\n        mqttStatus[topic] = (json && typeof json.val !== 'undefined') ? json.val : state;\n\n        /* istanbul ignore else */\n        if (mqttCallbacks[topic]) {\n            mqttCallbacks[topic].forEach(obj => {\n                const {attr, callback} = obj;\n                /* istanbul ignore else */\n                if (typeof callback === 'function') {\n                    /* istanbul ignore else */\n                    if (attr) {\n                        callback(json ? oe.getProp(json, attr) : state);\n                    } else {\n                        callback(state);\n                    }\n                }\n            });\n        }\n        // Topics array Used for autocomplete in web ui)\n        if (topics.indexOf(topic) === -1 && topic !== (config.name + '/connected')) {\n            topics.push(topic);\n        }\n    });\n\n    // Load and create all accessories\n    log.info('loading HomeKit to MQTT mapping file ' + config.mapfile);\n    mapping = JSON.parse(fs.readFileSync(config.mapfile));\n    convertMapping();\n    accCount = 0;\n    let accCountBridged = 0;\n    Object.keys(mapping).forEach(id => {\n        const accConfig = mapping[id];\n        accConfig.id = id;\n        const acc = newAccessory(accConfig);\n\n        let cam = false;\n        const camName = accConfig.name;\n        accConfig.services.forEach((s, i) => {\n            if (s.service === 'CameraRTSPStreamManagement') {\n                cam = true;\n            }\n            if (!addService[s.service]) {\n                loadService(s.service);\n            }\n            if (!s.json) {\n                s.json = {};\n            }\n            log.debug('adding service', s.service, 'to accessory', accConfig.name);\n            addService[s.service](acc, s, String(i));\n        });\n\n        if (cam) {\n            nextport(config.port, port => {\n                const username = mac(acc.UUID);\n                log.debug('hap publishing camera accessory ' + accConfig.name);\n                acc.publish({\n                    username,\n                    port,\n                    pincode: config.c,\n                    category: Accessory.Categories.CAMERA\n                });\n\n                log.debug('hap publishing camera accessory \"' + camName + '\" username=' + username, 'port=' + port,\n                    'pincode=' + config.c, 'setupURI=' + acc.setupURI());\n                acc._server.on('listening', () => {\n                    bridgeListening = true;\n                    mqttPub(config.name + '/connected', '2', {retain: true});\n                    log('hap camera', camName, 'listening on port', port);\n\n                    console.log('  \\nScan this code with your HomeKit app on your iOS device to pair with', camName);\n                    qrcode.generate(acc.setupURI());\n                    console.log('  ');\n                });\n\n                /* istanbul ignore next */\n                acc._server.on('pair', username => {\n                    log('hap camera', camName, 'paired', username);\n                });\n\n                /* istanbul ignore next */\n                acc._server.on('unpair', username => {\n                    log('hap camera', camName, 'unpaired', username);\n                });\n\n                /* istanbul ignore next */\n                acc._server.on('verify', () => {\n                    log('hap camera', camName, 'verify');\n                });\n            });\n            accCount++;\n        } else {\n            log.debug('addBridgedAccessory ' + accConfig.name);\n            bridge.addBridgedAccessory(acc);\n            accCountBridged++;\n        }\n    });\n    log.info('hap created', accCount, 'Camera Accessories and', accCountBridged, 'Bridged Accessories.');\n\n    bridge.publish({\n        username: config.username,\n        port: config.port,\n        pincode: config.c,\n        category: Accessory.Categories.OTHER\n    });\n    log.debug('hap publishing bridge \"' + config.bridgename + '\" username=' + config.username, 'port=' + config.port,\n        'pincode=' + config.c, 'setupURI=' + bridge.setupURI());\n\n    bridge._server.on('listening', () => {\n        bridgeListening = true;\n        mqttPub(config.name + '/connected', '2', {retain: true});\n        log('hap Bridge listening on port', config.port);\n\n        console.log('\\nScan this code with your HomeKit app on your iOS device to pair with the bridge');\n        qrcode.generate(bridge.setupURI());\n        console.log('Or enter this code with your HomeKit app on your iOS device to pair with homekit2mqtt:');\n        console.log(chalk.black.bgWhite('                       '));\n        console.log(chalk.black.bgWhite('    ┌────────────┐     '));\n        console.log(chalk.black.bgWhite('    │ ' + config.pincode + ' │     '));\n        console.log(chalk.black.bgWhite('    └────────────┘     '));\n        console.log(chalk.black.bgWhite('                       '));\n        console.log('');\n    });\n\n    bridge._server.on('pair', username => {\n        log('hap bridge paired', username);\n    });\n\n    /* istanbul ignore next */\n    bridge._server.on('unpair', username => {\n        log('hap bridge unpaired', username);\n    });\n\n    /* istanbul ignore next */\n    bridge._server.on('verify', () => {\n        log('hap bridge verify');\n    });\n}\n\nfunction saveMapping() {\n    fs.writeFileSync(config.mapfile, JSON.stringify(mapping, null, '  '));\n    log.info('saved config to', config.mapfile);\n}\n\nlet isStarted = false;\n\nfunction start() {\n    /* istanbul ignore if */\n    if (isStarted) {\n        log.error('already started');\n        return;\n    }\n    isStarted = true;\n    log.debug('mqtt unsubscribe #');\n    mqtt.unsubscribe('#');\n    createBridge();\n}\n\n/* istanbul ignore if */\nif (config.disableWeb) {\n    createBridge();\n} else {\n    // Get all retained messages (used for autocomplete in web ui)\n    log.debug('mqtt subscribe #');\n    mqtt.subscribe('#');\n    let retainTimeout = setTimeout(start, 1000);\n    mqtt.on('message', (topic, payload, msg) => {\n        if (isStarted) {\n            return;\n        }\n        if (msg.retain) {\n            clearTimeout(retainTimeout);\n            retainTimeout = setTimeout(start, 1000);\n        }\n        if (topics.indexOf(topic) === -1 && topic !== config.name + '/connected') {\n            topics.push(topic);\n        }\n    });\n\n    app.listen(config.webPort, () => {\n        log.info('http server listening on port', config.webPort);\n    });\n\n    app.use(basicAuth({\n        users: {homekit: config.pincode},\n        challenge: true,\n        realm: 'homekit2mqtt ui'\n    }));\n\n    /* istanbul ignore next */\n    app.get('/', (req, res) => {\n        res.redirect(301, '/ui');\n    });\n    app.use('/ui', express.static(path.join(__dirname, '/ui')));\n    app.use('/services.json', express.static(path.join(__dirname, '/services.json')));\n\n    module.paths.forEach(folder => {\n        app.use('/node_modules', express.static(folder));\n    });\n\n    app.get('/topics', (req, res) => {\n        log.info('http > topics');\n        res.send(JSON.stringify(topics));\n    });\n\n    app.get('/categories', (req, res) => {\n        log.info('http > categories');\n        res.send(JSON.stringify(HAP.Accessory.Categories));\n    });\n\n    app.get('/config', (req, res) => {\n        log.info('http > config');\n        res.send(JSON.stringify(mapping));\n    });\n\n    app.post('/config', bodyParser.json(), (req, res) => {\n        log.info('http < config');\n        mapping = req.body;\n        saveMapping();\n        res.send('ok');\n    });\n\n    app.get('/quit', (req, res) => {\n        log.info('http < quit');\n        res.send('ok');\n        setTimeout(() => {\n            process.exit(0);\n        }, 250);\n    });\n}\n"]}