Files
ring-mqtt/init-ring-mqtt.js
tsightler b8338e30de Release 5.1.0 (#537)
* Use MQTT for start-stream debug messages
* Fix ANSI colors
* Refactor event URL management
* Fix subscription detection
* Improve event URL expiry handling by parsing Amazon S3 expire time
* Convert to ESM/replace colors with chalk
* Force colors for chalk
* Migrate to ESM
* Fix stop of keepalive stream
* Add transcoded event selections
* Update event URL on raw/trancoded toggle
* Switch to per-camera livecall threads
* Customized WebRTC functions
Mostly copied from ring-client-api with port to pure Javascript, removal of unneeded features and additional debugging modified for use as worker thread with ring-mqtt.  Allows easier testing with updated Werift versions.
* Add nightlight enable/disable
* Include nightlight state as attribute
* Only pro versions have nightlight
* Tweak battery level reporting for dual battery cameras
* Release 5.1.0
2023-02-02 20:59:09 -05:00

109 lines
3.9 KiB
JavaScript

#!/usr/bin/env node
import fs from 'fs'
import { dirname } from 'path'
import { fileURLToPath } from 'url'
import { readFile } from 'fs/promises'
import writeFileAtomic from 'write-file-atomic'
import { createHash, randomBytes } from 'crypto'
import { RingRestClient } from 'ring-client-api/rest-client'
import { requestInput } from './node_modules/ring-client-api/lib/util.js'
async function getRefreshToken() {
let generatedToken
const email = await requestInput('Email: ')
const password = await requestInput('Password: ')
const restClient = new RingRestClient({ email, password })
try {
await restClient.getCurrentAuth()
} catch(err) {
if (restClient.using2fa) {
console.log('Username/Password was accepted, waiting for 2FA code to be entered.')
} else {
throw(err.message)
}
}
while(!generatedToken) {
const code = await requestInput('2FA Code: ')
try {
generatedToken = await restClient.getAuth(code)
return generatedToken.refresh_token
} catch(err) {
throw('Failed to validate the entered 2FA code. (error: invalid_code)')
}
}
}
const main = async() => {
let refresh_token
let stateData = {}
// If running in Docker set state file path as appropriate
const stateFile = (fs.existsSync('/etc/cont-init.d/ring-mqtt.sh'))
? '/data/ring-state.json'
: dirname(fileURLToPath(new URL(import.meta.url)))+'/ring-state.json'
const configFile = (fs.existsSync('/etc/cont-init.d/ring-mqtt.sh'))
? '/data/config.json'
: dirname(fileURLToPath(new URL(import.meta.url)))+'/config.json'
if (fs.existsSync(stateFile)) {
console.log('Reading latest data from state file: '+stateFile)
try {
stateData = JSON.parse(await readFile(stateFile))
} catch(err) {
console.log(err.message)
console.log('Saved state file '+stateFile+' exist but could not be parsed!')
console.log('To create new state file please rename/delete existing file and re-run this tool.')
process.exit(1)
}
}
try {
refresh_token = await getRefreshToken()
} catch(err) {
console.log(err)
console.log('Please re-run this tool to retry authentication.')
process.exit(1)
}
stateData.ring_token = refresh_token
if (!stateData.hasOwnProperty('systemId') || (stateData.hasOwnProperty('systemId') && !stateData.systemId)) {
stateData.systemId = (createHash('sha256').update(randomBytes(32)).digest('hex'))
}
try {
await writeFileAtomic(stateFile, JSON.stringify(stateData))
console.log('State file ' +stateFile+ ' saved with updated refresh token.')
} catch (err) {
console.log('Saving state file '+stateFile+' failed with error: ')
console.log(err)
}
if (!fs.existsSync(configFile)) {
try {
const configData = {
"mqtt_url": "mqtt://localhost:1883",
"mqtt_options": "",
"livestream_user": "",
"livestream_pass": "",
"disarm_code": "",
"enable_cameras": true,
"enable_modes": false,
"enable_panic": false,
"hass_topic": "homeassistant/status",
"ring_topic": "ring",
"location_ids": []
}
const mqttUrl = await requestInput('MQTT URL (enter to skip and edit config manually): ')
configData.mqtt_url = mqttUrl ? mqttUrl : configData.mqtt_url
await writeFileAtomic(configFile, JSON.stringify(configData, null, 4))
console.log('New config file written to '+configFile)
} catch (err) {
console.log('Failed to create new config file at '+stateFile)
conslog.log(err)
}
}
}
main()