homebridge-rachio-irrigation
Version:
Rachio Irrigation System platform plugin for [Homebridge](https://github.com/nfarina/homebridge).
1,124 lines (1,088 loc) • 33.8 kB
JavaScript
//// Public API info https://rachio.readme.io/v1.0/docs
//// Public API info https://rachio.readme.io/v2.0/docs
'use strict'
let axios = require('axios')
let api_endpoint = 'https://api.rach.io/1/public'
let alt_api_endpoint = 'https://cloud-rest.rach.io'
class RachioAPI {
constructor(platform, log) {
this.log = log
this.platform = platform
}
async getPersonInfo(token) {
try {
this.log.debug('Retrieving Person Info')
let response = await axios({
method: 'get',
baseURL: api_endpoint,
url: '/person/info/',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
responseType: 'json'
}).catch(err => {
this.log.error('Error getting person, Status %s', err.message)
this.log.debug(JSON.stringify(err, null, 2))
if (err.response) {
this.log.warn(JSON.stringify(err.response.data, null, 2))
}
throw err.code
})
if (response.status == 200) {
if (this.platform.showAPIMessages) {
this.log.debug('get person info response', JSON.stringify(response.data, null, 2))
}
return response.data
}
} catch (err) {
//this.log.error('Error retrieving personId \n%s', err)
throw err
}
}
async getPersonId(token, personId) {
try {
this.log.debug('Retrieving Person ID')
let response = await axios({
method: 'get',
baseURL: api_endpoint,
url: `/person/${personId}`,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
responseType: 'json'
}).catch(err => {
this.log.error('Error getting device %s', err.message)
this.log.debug(JSON.stringify(err, null, 2))
if (err.response) {
this.log.warn(JSON.stringify(err.response.data, null, 2))
}
throw err.code
})
if (response.status == 200) {
if (this.platform.showAPIMessages) {
this.log.debug('get person id response', JSON.stringify(response.data, null, 2))
}
return response.data
}
} catch (err) {
//this.log.error('Error retrieving deviceId \n%s', err)
throw err
}
}
async getPropertyEntity(token, resource, id) {
try {
this.log.debug('Getting Property info')
let response = await axios({
method: 'get',
baseURL: alt_api_endpoint,
url: `property/findPropertyByEntity`,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
params: {
[`resource_id.${resource}`]: `${id}`
},
responseType: 'json'
}).catch(err => {
this.log.error('Error getting property info %s', err.message)
this.log.debug(JSON.stringify(err, null, 2))
if (err.response) {
this.log.warn(JSON.stringify(err.response.data, null, 2))
}
return err.response
})
if (response.status == 200) {
if (this.platform.showAPIMessages) {
this.log.debug('get property info response', JSON.stringify(response.data, null, 2))
}
return response.data
}
} catch (err) {
this.log.error('Error getting property info \n%s', err)
}
}
async getDevice(token, device) {
try {
this.log.debug('Getting current device', device)
let response = await axios({
method: 'get',
baseURL: alt_api_endpoint,
url: `/device/getDevice/${device}`,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
responseType: 'json'
}).catch(err => {
this.log.error('Error getting device %s', err.message)
this.log.debug(JSON.stringify(err, null, 2))
if (err.response) {
this.log.warn(JSON.stringify(err.response.data, null, 2))
}
throw err.code
})
if (response.status == 200) {
if (this.platform.showAPIMessages) {
this.log.debug('get device response', JSON.stringify(response.data, null, 2))
}
return response.data
}
} catch (err) {
//this.log.error('Error getting device \n%s', err)
throw err
}
}
async getDeviceState(token, device) {
try {
this.log.debug('Getting current device state', device)
let response = await axios({
method: 'get',
baseURL: alt_api_endpoint,
url: `/device/getDeviceState/${device}`,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
responseType: 'json'
}).catch(err => {
this.log.error('Error getting device state %s', err.message)
this.log.debug(JSON.stringify(err, null, 2))
if (err.response) {
this.log.warn(JSON.stringify(err.response.data, null, 2))
}
throw err.code
})
if (response.status == 200) {
if (this.platform.showAPIMessages) {
this.log.debug('get device state response', JSON.stringify(response.data, null, 2))
}
return response.data
}
} catch (err) {
//this.log.error('Error getting device state \n%s', err)
throw err
}
}
async getDeviceDetails(token, device) {
try {
this.log.debug('Getting current device state', device)
let response = await axios({
method: 'get',
baseURL: alt_api_endpoint,
url: `/device/getDeviceDetails/${device}`,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
responseType: 'json'
}).catch(err => {
this.log.error('Error getting device details %s', err.message)
this.log.debug(JSON.stringify(err, null, 2))
if (err.response) {
this.log.warn(JSON.stringify(err.response.data, null, 2))
}
throw err.code
})
if (response.status == 200) {
if (this.platform.showAPIMessages) {
this.log.debug('get device details response', JSON.stringify(response.data, null, 2))
}
return response.data
}
} catch (err) {
//this.log.error('Error getting device details \n%s', err)
throw err
}
}
async getDeviceInfo(token, device) {
try {
this.log.debug('Getting current device state', device)
let response = await axios({
method: 'get',
baseURL: api_endpoint,
url: `/device/${device}`,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
responseType: 'json'
}).catch(err => {
this.log.error('Error getting device info %s', err.message)
this.log.debug(JSON.stringify(err, null, 2))
if (err.response) {
this.log.warn(JSON.stringify(err.response.data, null, 2))
}
throw err.code
})
if (response.status == 200) {
if (this.platform.showAPIMessages) {
this.log.debug('get device info response', JSON.stringify(response.data, null, 2))
}
return response.data
}
} catch (err) {
//this.log.error('Error getting device info \n%s', err)
throw err
}
}
async getLocationList(token) {
try {
this.log.debug('Getting Location List')
let response = await axios({
method: 'get',
baseURL: alt_api_endpoint,
url: '/location/listLocations/true',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
responseType: 'json'
}).catch(err => {
this.log.error('Error getting location list %s', err.message)
this.log.debug(JSON.stringify(err, null, 2))
if (err.response) {
this.log.warn(JSON.stringify(err.response.data, null, 2))
}
throw err.code
})
if (response.status == 200) {
if (this.platform.showAPIMessages) {
this.log.debug('get list locations response', JSON.stringify(response.data, null, 2))
}
return response.data
}
} catch (err) {
//this.log.error('Error getting location list \n%s', err)
throw err
}
}
async currentSchedule(token, device) {
try {
this.log.debug('Getting current schedule', device)
let response = await axios({
method: 'get',
baseURL: api_endpoint,
url: `/device/${device}/current_schedule`,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
responseType: 'json'
}).catch(err => {
this.log.error('Error getting schedule %s', err.message)
this.log.debug(JSON.stringify(err, null, 2))
if (err.response) {
this.log.warn(JSON.stringify(err.response.data, null, 2))
}
return err.response
})
this.log.debug('status', response.data.status || 'No active schedule')
if (response.status == 200) {
if (this.platform.showAPIMessages) {
this.log.debug('get current schedule response', JSON.stringify(response.data, null, 2))
}
return response
}
} catch (err) {
this.log.error('Error getting current schedule \n%s', err)
}
}
async deviceStandby(token, device, state) {
try {
this.log.debug('Setting Standby Mode on', device.id)
let response = await axios({
method: 'put',
baseURL: api_endpoint,
url: `/device/${state}`,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
data: {
id: device.id
},
responseType: 'json'
}).catch(err => {
this.log.error('Error setting standby to %s %s', state, err.message)
this.log.warn(JSON.stringify(err.response.data, null, 2))
this.log.debug(JSON.stringify(err, null, 2))
})
this.log.debug('device standby response status', response.status)
return response
} catch (err) {
this.log.error('Error setting standby \n%s', err)
}
}
async startZone(token, zone, runtime) {
try {
this.log.debug('Starting Zone', zone)
let response = await axios({
method: 'put',
baseURL: api_endpoint,
url: '/zone/start',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
data: {
id: zone,
duration: runtime
},
responseType: 'json'
}).catch(err => {
this.log.error('Error sending start zone %s', err.message)
this.log.warn(JSON.stringify(err.response.data, null, 2))
this.log.debug(JSON.stringify(err, null, 2))
})
this.log.debug('start response', response.status)
return response
} catch (err) {
this.log.error('Error Starting Zone \n%s', err)
}
}
async startSchedule(token, schedule) {
try {
this.log.debug('Starting Schedule', schedule)
let response = await axios({
method: 'put',
baseURL: api_endpoint,
url: '/schedulerule/start',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
data: {
id: schedule
},
responseType: 'json'
}).catch(err => {
this.log.error('Error sending start schedule %s', err.message)
this.log.warn(JSON.stringify(err.response.data, null, 2))
this.log.debug(JSON.stringify(err, null, 2))
})
this.log.debug('start schedule response', response.status)
return response
} catch (err) {
this.log.error('Error Starting Schedule \n%s', err)
}
}
async stopDevice(token, deviceId) {
try {
this.log.debug('Stopping', deviceId)
let response = await axios({
method: 'put',
baseURL: api_endpoint,
url: '/device/stop_water',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
data: {
id: deviceId
},
responseType: 'json'
}).catch(err => {
this.log.error('Error sending stop %s', err.message)
this.log.warn(JSON.stringify(err.response.data, null, 2))
this.log.debug(JSON.stringify(err, null, 2))
})
this.log.debug('stop response', response.status)
return response
} catch (err) {
this.log.error('Error Stopping Device \n%s', err)
}
}
async startMultipleZone(token, zones, duration) {
try {
let body = []
//this.log.debug('Starting Multiple Zones', zones)
zones.forEach((zone, index) => {
if (zone.enabled) {
body.push({
name: zone.name,
id: zone.id,
duration: duration,
sortOrder: index
})
}
})
this.log.debug('multiple run data', JSON.stringify(body, null, 2))
let response = await axios({
method: 'put',
baseURL: api_endpoint,
url: '/zone/start_multiple',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
data: {
zones: body
},
responseType: 'json'
}).catch(err => {
this.log.error('Error sending start %s', err.message)
this.log.warn(JSON.stringify(err.response.data, null, 2))
this.log.debug(JSON.stringify(err, null, 2))
})
this.log.debug('start multiple response', response.status)
return response
} catch (err) {
this.log.error('Error Starting Multiple Zones \n%s', err)
}
}
async listBaseStations(token, userid) {
try {
this.log.debug('Getting Base Stations List')
let response = await axios({
method: 'get',
baseURL: alt_api_endpoint,
url: `/valve/listBaseStations/${userid}`,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
responseType: 'json'
}).catch(err => {
this.log.error('Error getting base stations list %s', err.message)
this.log.debug(JSON.stringify(err, null, 2))
if (err.response) {
this.log.warn(JSON.stringify(err.response.data, null, 2))
}
return err.response
})
if (response.status == 200) {
if (this.platform.showAPIMessages) {
this.log.debug('get base stations list response', JSON.stringify(response.data, null, 2))
}
return response.data
}
} catch (err) {
this.log.error('Error getting base stations list \n%s', err)
}
}
async getBaseStation(token, baseStationId) {
try {
this.log.debug('Getting Base Station')
let response = await axios({
method: 'get',
baseURL: alt_api_endpoint,
url: `/valve/getBaseStation/${baseStationId}`,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
responseType: 'json'
}).catch(err => {
this.log.error('Error getting base station %s', err.message)
this.log.debug(JSON.stringify(err, null, 2))
if (err.response) {
this.log.warn(JSON.stringify(err.response.data, null, 2))
}
return err.response
})
if (response.status == 200) {
if (this.platform.showAPIMessages) {
this.log.debug('get base station response', JSON.stringify(response.data, null, 2))
}
return response.data
}
} catch (err) {
this.log.error('Error getting base station \n%s', err)
}
}
async listValves(token, baseStationId) {
try {
this.log.debug('Getting valves List')
let response = await axios({
method: 'get',
baseURL: alt_api_endpoint,
url: `/valve/listValves/${baseStationId}`,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
responseType: 'json'
}).catch(err => {
this.log.error('Error getting valves list %s', err.message)
this.log.debug(JSON.stringify(err, null, 2))
if (err.response) {
this.log.warn(JSON.stringify(err.response.data, null, 2))
}
return err.response
})
if (response.status == 200) {
if (this.platform.showAPIMessages) {
this.log.debug('get valves list response', JSON.stringify(response.data, null, 2))
}
return response.data
}
} catch (err) {
this.log.error('Error getting valves list \n%s', err)
}
}
async getValve(token, valveId) {
try {
this.log.debug('Getting Valve')
let response = await axios({
method: 'get',
baseURL: alt_api_endpoint,
url: `/valve/getValve/${valveId}`,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
responseType: 'json'
}).catch(err => {
this.log.error('Error getting valve %s', err.message)
this.log.debug(JSON.stringify(err, null, 2))
if (err.response) {
this.log.warn(JSON.stringify(err.response.data, null, 2))
}
return err.response
})
if (response.status == 200) {
if (this.platform.showAPIMessages) {
this.log.debug('get valve response', JSON.stringify(response.data, null, 2))
}
this.log.debug('%s API calls remaining', response.headers['x-ratelimit-remaining'])
return response
}
} catch (err) {
this.log.error('Error getting valve \n%s', err)
}
}
async startWatering(token, valveId, runtime) {
try {
this.log.debug('Start Watering', valveId)
let response = await axios({
method: 'put',
baseURL: alt_api_endpoint,
url: '/valve/startWatering',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
data: {
valveId: valveId,
durationSeconds: runtime
},
responseType: 'json'
}).catch(err => {
this.log.error('Error sending start watering %s', err.message)
this.log.warn(JSON.stringify(err.response.data, null, 2))
this.log.debug(JSON.stringify(err, null, 2))
})
this.log.debug('start watering response', response.status)
return response
} catch (err) {
this.log.error('Error starting watering \n%s', err)
}
}
async stopWatering(token, valveId) {
try {
this.log.debug('Stop Watering', valveId)
let response = await axios({
method: 'put',
baseURL: alt_api_endpoint,
url: '/valve/stopWatering',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
data: {
valveId: valveId
},
responseType: 'json'
}).catch(err => {
this.log.error('Error sending stop watering %s', err.message)
this.log.warn(JSON.stringify(err.response.data, null, 2))
this.log.debug(JSON.stringify(err, null, 2))
})
this.log.debug('stop watering response', response.status)
return response
} catch (err) {
this.log.error('Error stopping watering \n%s', err)
}
}
async setDefaultRuntime(token, valveId, defaultRuntime) {
try {
this.log.debug('Set Default Runtime', valveId)
let response = await axios({
method: 'put',
baseURL: alt_api_endpoint,
url: '/valve/setDefaultRuntime',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
data: {
id: valveId,
defaultRuntimeSeconds: defaultRuntime
},
responseType: 'json'
}).catch(err => {
this.log.error('Error setting default runtime %s', err.message)
this.log.warn(JSON.stringify(err.response.data, null, 2))
this.log.debug(JSON.stringify(err, null, 2))
})
this.log.debug('set default runtime response', response.status)
return response
} catch (err) {
this.log.error('Error setting default runtime \n%s', err)
}
}
async listPrograms(token, valveId) {
try {
this.log.debug('Set Default Runtime', valveId)
let response = await axios({
method: 'get',
baseURL: alt_api_endpoint,
url: `program/listPrograms/${valveId}`,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
responseType: 'json'
}).catch(err => {
this.log.error('Error setting default runtime %s', err.message)
this.log.warn(JSON.stringify(err.response.data, null, 2))
this.log.debug(JSON.stringify(err, null, 2))
})
this.log.debug('set default runtime response', response.status)
return response
} catch (err) {
this.log.error('Error setting default runtime \n%s', err)
}
}
async configureWebhooks(token, external_webhook_address, delete_webhooks, device_id, device_name, webhook_key) {
try {
/*********************************************
Event Type options from get events
"id": 5 ="DEVICE_STATUS_EVENT"
"id": 6 ="RAIN_DELAY_EVENT"
"id": 7 ="WEATHER_INTELLIGENCE_EVENT"
"id": 8 ="WATER_BUDGET"
"id": 9= "SCHEDULE_STATUS_EVENT"
"id": 8 ="WATER_BUDGET"
"id": 10="ZONE_STATUS_EVENT"
"id": 11="RAIN_SENSOR_DETECTION_EVENT"
"id": 12="ZONE_DELTA"
"id": 14="DELTA"
**********************************************/
let events = [{id: 5}, {id: 6}] //eventTypes: [{id: 5}, {id: 10}, {id: 6}, {id: 7}, {id: 9}]
this.log.info('Configuring Rachio webhooks for controller ID %s', device_id)
let response = await axios({
method: 'get',
baseURL: api_endpoint,
url: '/notification/' + device_id + '/webhook',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
responseType: 'json'
}).catch(err => {
this.log.debug(JSON.stringify(err, null, 2))
this.log.error('Error retrieving webhooks %s', err.message)
if(err.response){
this.log.warn(JSON.stringify(err.response.data, null, 2));
}
throw err.code;
})
if (response.status == 200) {
if (this.platform.showAPIMessages) {
this.log.debug('configured webhooks response', JSON.stringify(response.data, null, 2))
}
}
let webhooks = response.data
if (this.platform.showAPIMessages) {
this.log.debug('configured webhooks response', JSON.stringify(response.data, null, 2))
}
if (!webhooks || !Array.isArray(webhooks)) {
return
}
if (delete_webhooks) {
//delete exsisting webhooks
webhooks.forEach(async webhook => {
if (webhook.externalId == webhook_key) {
return
} //Skip the current webhook and let it be updated
response = await axios({
method: 'delete',
baseURL: api_endpoint,
url: '/notification/webhook/' + webhook.id,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
responseType: 'json'
}).catch(err => {
this.log.debug(JSON.stringify(err, null, 2))
this.log.error('Error deleting old webhook $s : $s', webhook.id, err.message)
if(err.response){
this.log.warn(JSON.stringify(err.response.data, null, 2));
}
throw err.code;
})
if (response.status == 204) {
this.log.debug('Successfully deleted old webhook %s', webhook.id)
}
})
}
let updateWebhook = false
let count = 0
webhooks.forEach(async webhook => {
if (webhook.externalId == webhook_key || webhook.url == external_webhook_address) {
count++
if (count == 1) {
updateWebhook = webhook
return
}
response = await axios({
method: 'delete',
baseURL: api_endpoint,
url: '/notification/' + 'webhook/' + webhook.id,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
responseType: 'json'
}).catch(err => {
this.log.debug(JSON.stringify(err, null, 2))
this.log.error('Error deleting old webhook $s : $s', webhook.id, err.message)
if(err.response){
this.log.warn(JSON.stringify(err.response.data, null, 2));
}
throw err.code;
})
if (response.status == 204) {
this.log.debug('Successfully deleted extra webhook %s', webhook.id)
}
}
})
if (updateWebhook) {
this.log.info('Updating Rachio Webhook ID %s, for destination %s', updateWebhook.id, external_webhook_address)
response = await axios({
method: 'put',
baseURL: api_endpoint,
url: '/notification/webhook/',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
responseType: 'json',
data: {
id: updateWebhook.id,
externalId: webhook_key,
url: external_webhook_address,
eventTypes: events
}
}).catch(err => {
this.log.debug(JSON.stringify(err, null, 2))
this.log.error('Error updating exsisting webhook $s : $s', updateWebhook.id, err.message)
if(err.response){
this.log.warn(JSON.stringify(err.response.data, null, 2));
}
throw err.code;
})
} else {
this.log.info('Creating Webhook for ' + external_webhook_address)
response = await axios({
method: 'post',
baseURL: api_endpoint,
url: '/notification/webhook/',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
responseType: 'json',
data: {
device: {id: device_id},
externalId: webhook_key,
url: external_webhook_address,
eventTypes: events
}
}).catch(err => {
this.log.debug(JSON.stringify(err, null, 2))
this.log.error('Error configuring new webhook $s : $s', updateWebhook.id, err, message)
if(err.response){
this.log.warn(JSON.stringify(err.response.data, null, 2));
}
throw err.code;
})
}
if (this.platform.showAPIMessages) {
this.log.debug('create/update webhooks response', JSON.stringify(response.data, null, 2))
}
let test_webhook_url = external_webhook_address + '/test'
if (response.status == 200) {
this.log.success('Successfully configured webhook for %s with external ID "%s" ', device_name, webhook_key)
this.log.info(
'To test Webhook setup, navigate to %s to ensure port forwarding is configured correctly. ' +
'\nNote: For local config this will not work from this server, you cannot be connected to the same router doing the fowarding. ' +
'\nThe best way to test this is from a cell phone, with WiFi off.',
test_webhook_url
)
}
return
} catch (err) {
this.log.error('Error configuring webhook for %s \n%s', device_name, err)
}
}
async configureWebhooksv2(token, external_webhook_address, delete_webhooks, device_id, device_name, webhook_key, type) {
try {
/*********************************************
Event Type options from webhook info
"SCHEDULE_STARTED_EVENT",
"SCHEDULE_STOPPED_EVENT",
"SCHEDULE_COMPLETED_EVENT",
"DEVICE_ZONE_RUN_STARTED_EVENT",
"DEVICE_ZONE_RUN_PAUSED_EVENT",
"DEVICE_ZONE_RUN_STOPPED_EVENT",
"DEVICE_ZONE_RUN_COMPLETED_EVENT",
"CLIMATE_SKIP_NOTIFICATION_EVENT",
"FREEZE_SKIP_NOTIFICATION_EVENT",
"RAIN_SKIP_NOTIFICATION_EVENT",
"WIND_SKIP_NOTIFICATION_EVENT",
"NO_SKIP_NOTIFICATION_EVENT"
"VALVE_RUN_START_EVENT",
"VALVE_RUN_END_EVENT"
"PROGRAM_RAIN_SKIP_CREATED_EVENT",
"PROGRAM_RAIN_SKIP_CANCELED_EVENT"
**********************************************/
let param
let resource
let event
let events
if (type == 'irrigation_controller_id'){
param = {
'resource_id.irrigation_controller_id': device_id
}
resource = {
irrigation_controller_id: device_id
}
events = [
'DEVICE_ZONE_RUN_STARTED_EVENT',
'DEVICE_ZONE_RUN_PAUSED_EVENT',
'DEVICE_ZONE_RUN_STOPPED_EVENT',
'DEVICE_ZONE_RUN_COMPLETED_EVENT',
'SCHEDULE_STARTED_EVENT',
'SCHEDULE_STOPPED_EVENT',
'SCHEDULE_COMPLETED_EVENT'
]
event = {
event_types: events
}
} else if (type == 'valve_id') {
param = {
'resource_id.valve_id': device_id
}
resource = {
valve_id: device_id
}
events = [
'VALVE_RUN_START_EVENT',
'VALVE_RUN_END_EVENT'
]
event = {
event_types: events
}
}
this.log.debug('Configuring Rachio webhooks v2 for controller ID %s', device_id)
let response = await axios({
method: 'get',
baseURL: alt_api_endpoint,
url: 'webhook/listWebhooks',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
params: param,
responseType: 'json'
}).catch(err => {
this.log.debug(JSON.stringify(err, null, 2))
this.log.error('Error retrieving webhooks %s', err.message)
if(err.response){
this.log.warn(JSON.stringify(err.response.data, null, 2));
}
throw err.code;
})
if (response.status == 200) {
if (this.platform.showAPIMessages) {
this.log.debug('configured webhooks v2 response', JSON.stringify(response.data, null, 2))
}
}
let webhooks = response.data.webhooks
if (this.platform.showAPIMessages) {
this.log.debug('configured webhooks v2 response', JSON.stringify(response.data, null, 2))
}
if (!webhooks || !Array.isArray(webhooks)) {
return
}
if (delete_webhooks) {
//delete exsisting webhooks
webhooks.forEach(async webhook => {
if (webhook.externalId == webhook_key) {
return
} //Skip the current webhook and let it be updated
response = await axios({
method: 'delete',
baseURL: alt_api_endpoint,
url: 'webhook/deleteWebhook/' + webhook.id,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
responseType: 'json'
}).catch(err => {
this.log.debug(JSON.stringify(err, null, 2))
this.log.error('Error deleting old webhook $s : $s', webhook.id, err.message)
if(err.response){
this.log.warn(JSON.stringify(err.response.data, null, 2));
}
throw err.code;
})
if (response.status == 204) {
this.log.debug('Successfully deleted old v2 webhook %s', webhook.id)
}
})
}
let updateWebhook = false
let count = 0
webhooks.forEach(async webhook => {
if (webhook.externalId == webhook_key || webhook.url == external_webhook_address) {
count++
if (count == 1) {
updateWebhook = webhook
return
}
response = await axios({
method: 'delete',
baseURL: alt_api_endpoint,
url: 'webhook/deleteWebhook/' + webhook.id,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
responseType: 'json'
}).catch(err => {
this.log.debug(JSON.stringify(err, null, 2))
this.log.error('Error deleting old v2 webhook $s : $s', webhook.id, err.message)
if(err.response){
this.log.warn(JSON.stringify(err.response.data, null, 2));
}
throw err.code;
})
if (response.status == 204) {
this.log.debug('Successfully deleted extra webhook %s', webhook.id)
}
}
})
if (updateWebhook) {
this.log.info('Updating Rachio Webhook ID %s, for destination %s', updateWebhook.id, external_webhook_address)
response = await axios({
method: 'put',
baseURL: alt_api_endpoint,
url: 'webhook/updateWebhook',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
responseType: 'json',
data: {
id: updateWebhook.id,
url: external_webhook_address,
externalId: {
data: webhook_key
},
resource_id: resource,
event_types: event,
}
}).catch(err => {
this.log.debug(JSON.stringify(err, null, 2))
this.log.error('Error updating exsisting v2 webhook $s : $s', updateWebhook.id, err.message)
if(err.response){
this.log.warn(JSON.stringify(err.response.data, null, 2));
}
throw err.code;
})
} else {
this.log.info('Creating Webhook for ' + external_webhook_address)
response = await axios({
method: 'post',
baseURL: alt_api_endpoint,
url: 'webhook/createWebhook',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': `${PluginName}/${PluginVersion}`
},
responseType: 'json',
data: {
resource_id: resource,
externalId: webhook_key,
url: external_webhook_address,
event_types: events,
}
}).catch(err => {
this.log.info(JSON.stringify(err, null, 2))
this.log.error('Error configuring new v2 webhook $s : $s', updateWebhook.id, err, message)
if(err.response){
this.log.warn(JSON.stringify(err.response.data, null, 2));
}
throw err.code;
})
}
if (this.platform.showAPIMessages) {
this.log.debug('create/update webhooks v2 response', JSON.stringify(response.data, null, 2))
}
let test_webhook_url = external_webhook_address + '/test'
if (response.status == 200) {
this.log.success('Successfully configured webhook for device id %s with external id "%s" ', device_name, webhook_key)
this.log.info(
'To test Webhook setup, navigate to %s to ensure port forwarding is configured correctly. ' +
'\nNote: For local config this will not work from this server, you cannot be connected to the same router doing the fowarding. ' +
'\nThe best way to test this is from a cell phone, with WiFi off.',
test_webhook_url
)
}
return
} catch (err) {
this.log.error('Error configuring webhook for device id %s \n%s', device_name, err)
}
}
}
module.exports = RachioAPI